元组是用来保存一组数据元素的复合数据类型,其中数据元素是要求为erlang的数据类型,单不一定要是相同的类型,元组使用封闭的花括号{}来定义,里面的元素有逗号隔开。

  例如: 1> {1,2,3}.

      2> {1,{2,3},4}.

      3> {1,[2,3],4}.

      4> {1,"23",4}.

  tuple 的bifs函数:

  erlang:tuple_size(Tuple) ->Length. Tuple 的长度

  erlang:element(i,Tuple) -> aton(). 选择第i个位置的元素

  erlang:setelement(i,Tuple,Aton) ->Tuple2, 修改Tuple中的第i个位置的值为Aton。

  参考lists,得出一些类似lists的函数:

-module(com_record).

%% ====================================================================
%% API functions
%% ====================================================================
-export([map/2,
get_name/1,
foreach/2,
foldl/3,
foldl2/4,
foldl_index/4,
merge/3,
merge/4,
any/2,
any/3,
tuple_merge/3,
put_pd_fields/2,
get_pd_fields/2
]).

-spec any(Pred, T) -> boolean() when
Pred :: fun((Elem::term() ) -> boolean()),
T :: tuple().

%% @doc like lists:any/1
any(Pred, Tuple) ->
any(Pred, Tuple, 2).

any(_, {}, _) -> false;
any(Pred, Tuple, Begin) ->
S = tuple_size(Tuple),
if S < Begin ->
false;
true ->
any__(Pred, Tuple, Begin, S)
end.

any__(Pred, Tuple, M, M) ->
Pred(element(M, Tuple));
any__(Pred, Tuple, N, M) ->
case Pred(element(M, Tuple)) of
true ->
true;
_ ->
any__(Pred, Tuple, N+1, M)
end.

%% @doc record map
-spec map(Func, Record) -> Record2 when
Record :: Tuple,
Record2 :: Tuple,
Func :: fun((term()) -> term()),
Tuple :: tuple().
map(Func, Record) ->
[Name| List] = erlang:tuple_to_list(Record),
List2 = lists:map(Func, List),
erlang:list_to_tuple([Name | List2]).

-compile({inline, [get_name/1]}).
%% @doc get record name.
-spec get_name(tuple()) -> atom().
get_name(Record) ->
erlang:element(1, Record).

%% @doc foreach element not include name.
-spec foreach(Fun, Record) -> ok when
Fun :: fun((term()) -> _),
Record :: tuple().
foreach(Fun, Record) when is_tuple(Record) ->
com_util:for(2, erlang:tuple_size(Record), Fun).

%% @doc foldl element not include name.
-spec foldl(Fun, Acc0, Record) -> Acc1 when
Fun :: fun((term(), AccIn) -> AccOut),
Acc0 :: term(),
Acc1 :: term(),
AccIn :: term(),
AccOut :: term(),
Record :: tuple().

%% @doc not aceess record name.
foldl(Func, Acc, Record) when is_function(Func,2) ->
case erlang:tuple_size(Record) of
1 -> Acc;
M ->
foldl_(Func, Acc, Record, 2, M)
end.

foldl2(Func, Acc, Record, Begin)
when is_function(Func, 2) ->
case erlang:tuple_size(Record) of
S when S < Begin -> Acc;
S ->
foldl_(Func, Acc, Record, Begin, S)
end.

foldl_(Func, Acc, Record, N, N) ->
Func(erlang:element(N, Record), Acc);
foldl_(Func, Acc, Record, N, M) ->
foldl_(Func,
Func(erlang:element(N, Record), Acc),
Record, N+1, M).

%% @doc same foldl2 but fun take 3 arg
foldl_index(Func, Acc, Record, Begin) ->
case erlang:tuple_size(Record) of
S when S < Begin -> Acc;
S ->
foldl_index_(Func, Acc, Record, Begin, S)
end.

%% @doc merge two same type record with func
%% two record must same type.
%% Fun argument is record elements
%% @usage
%% merage(fun(A,B) -> A + B end, {aa, 1,1,1} , {aa, 3,3,3})
%% -> {aa, 4,4,4}
-spec merge(Fun, Record1, Record2) -> RecordOut when
Fun :: fun((A, B) -> T),
Record1 :: RecordOut,
Record2 :: RecordOut,
RecordOut :: tuple(),
A :: term(),
B :: term(),
T :: term().

merge(Fun, Record1, Record2) when is_function(Fun, 2) ->
merge__(Fun, Record1, Record2, 2, {get_name(Record1)}).

merge(Fun, Record1, Record2, Begin) when is_function(Fun, 2) ->
merge__(Fun, Record1, Record2, Begin, {get_name(Record1)}).

tuple_merge(Fun, T1, T2) ->
merge__(Fun, T1, T2, 1, {}).

merge__(Fun, T1, T2, Begin, Acc) ->
com_util:fold(Begin,
erlang:tuple_size(T1),
fun(Index, RecordOut) ->
erlang:append_element(RecordOut,
Fun(erlang:element(Index, T1),
erlang:element(Index, T2)))
end,
Acc
).

foldl_index_(Func, Acc, Record, N, N) ->
Func(N, erlang:element(N, Record), Acc);
foldl_index_(Func, Acc, Record, N, M) ->
foldl_index_(Func,
Func(N, erlang:element(N, Record), Acc),
Record, N+1, M).

%% HACK 最好的元转换
%% @doc 存入进程字典 每个filed 都会在前面加上pd_ 的前缀
%% 每个进程字典都只能是单次赋值
put_pd_fields(Record, FieldsName)
when erlang:is_list(FieldsName),
erlang:is_tuple(Record) ->
lists:foldl(fun(FName, Index) ->
case erlang:put(erlang:list_to_atom("pd_" ++ erlang:atom_to_list(FName)),
erlang:element(Index, Record))
of
undefined -> ok;
Ov -> io:format("ERR recrod_put ~p not first ~p\n", [FName, Ov])
end,
Index+1
end,
2,
FieldsName).

%% @doc Record
-spec get_pd_fields(RecordName, [atom()]) -> RecordOut when
RecordName :: atom(),
RecordOut :: tuple().

get_pd_fields(RecordName, FieldsName)
when erlang:is_list(FieldsName) ->
lists:foldl(fun(FName, R) ->
erlang:append_element(R,
erlang:get(erlang:list_to_atom("pd_" ++ erlang:atom_to_list(FName))))
end,
{RecordName},
FieldsName).

%%%%%% TEST unit

%-define(TEST, 1).
-ifdef(TEST).
-include_lib("eunit/include/eunit.hrl").

-record(tt, {id, name, age}).

pd_fields_test() ->
R= #tt{id=32, name= <<"feof">>, age=[1,2,4]},
put_pd_fields(R, record_info(fields, tt)),
?assertEqual(32, get(pd_id)),
?assertEqual(<<"feof">>, get(pd_name)),
?assertEqual([1,2,4], get(pd_age)),

R2 = get_pd_fields(tt, record_info(fields, tt)),
?assertEqual(R2, R),

ok.

-endif.

j教你如何用erlang-tuple的更多相关文章

  1. 教你如何用PS制作多款按钮UI设计教程

    教你如何用PS制作多款按钮UI设计教程 本文教大家制作按钮的方法 LV. ★ 初入设计,学做按钮.只会套个底色,加个阴影,字体纯白,小聪明的弄个圆角. LV. ★★(描边.字体.内阴影) 看了很多案例 ...

  2. 说说erlang tuple和record结构

    erlang有两种复合结构.tuple和list,两者的区别是tuple子元素的个数是固定不变的.声明后就不能改变了.而list是可变的,能够通过[H|T]来取出或插入新元素. record有点像C/ ...

  3. 从原理到代码:大牛教你如何用 TensorFlow 亲手搭建一套图像识别模块 | AI 研习社

    从原理到代码:大牛教你如何用 TensorFlow 亲手搭建一套图像识别模块 | AI 研习社 PPT链接: https://pan.baidu.com/s/1i5Jrr1N 视频链接: https: ...

  4. 一篇文章教你如何用R进行数据挖掘

    一篇文章教你如何用R进行数据挖掘 引言 R是一种广泛用于数据分析和统计计算的强大语言,于上世纪90年代开始发展起来.得益于全世界众多 爱好者的无尽努力,大家继而开发出了一种基于R但优于R基本文本编辑器 ...

  5. 零元学Expression Design 4 - Chapter 5 教你如何用自制笔刷在5分钟内做出设计感效果

    原文:零元学Expression Design 4 - Chapter 5 教你如何用自制笔刷在5分钟内做出设计感效果 本章将教你如何运用笔刷与简单线条,只要5分钟,就能做出设计感效果 ? 本章将教你 ...

  6. Android | 教你如何用华为HMS MLKit 图像分割 SDK开发一个证件照DIY小程序

    Android | 教你如何用华为HMS MLKit 图像分割 SDK开发一个证件照DIY小程序 引子   上期给大家介绍了如何使用如何用华为HMS MLKit SDK 三十分钟在安卓上开发一个微笑抓 ...

  7. Android | 教你如何用代码一键实现银行卡绑定

    前言   小编前面几期文章分别给大家介绍了用代码实现微笑抓拍.证件照DIY.拍照翻译的功能开发(链接见文章末尾),本次小编给大家带来的是用代码一键实现银行卡识别与绑定功能. 银行卡识别的应用场景    ...

  8. 手把手教小白如何用css+js实现页面中图片放大展示效果

    1.前言      很多童鞋会在项目中遇到一些上传图片,展示图片的操作,但是图片呢有大有小,为了页面的美观,有时候我们需要将图片展示成固定宽高度,但是呢,领导就会说,我想看大图片,怎么办?想看就看呀, ...

  9. 一篇文章教你如何用 Python 记录日志

    前言: 这篇文章是我copy别人的,但是个人认为讲的真的很细致,有原理有实例,不仅仅只教你如何使用日志更会叫你知道日志的原理,真的非常棒,虽然文章很长,也许你不会认认真真读完, 但是当你遇到问题时这篇 ...

随机推荐

  1. 使用 mysqladmin debug 查看死锁信息

    使用 mysqladmin debug 查看死锁信息 mysqladmin -S /mysql/data/mysql.sock debug 然后在error日志中,会看到: 11 lock struc ...

  2. Linux Time_wait网络状态 调优

    Time_wait状态 表示收到了对方的FIN报文,并发送出了ACK报文,就等2MSL后即可回到CLOSED可用状态了. 如果FIN_WAIT_1状态下,收到了对方同时带FIN标志和ACK标志的报文时 ...

  3. JSOIWC2019游记

    世除我WC...都去广二了qaq,就我还在nj ycs至少也去了pkuwc啊 这个JSOIWC2019的内容看起来很水,进入条件简单,但窝啥都不会,肯定垫底 内容清单: 1.26 上午听机房dalao ...

  4. es日常维护

    1.查看es日志curl -XGET http://10.26.41.60:9200/xdm-logs-2018.08.22?pretty=true 2.删除es日志curl -XDELETE 'ht ...

  5. PLSQL远程连接数据库(亲测可试)

    一.准备工具: ORALCE数据库.PLSQL连接工具.确认网络正常 (我是在局域网中的,如果不是局域网,需要去ORACLE安装目录下找到sqlnet.ora 在里面找到 SQLNET.AUTHENT ...

  6. linux存储管理之自动挂在

    自动挂载 Automount ==================================================================================== ...

  7. Linux出现wrong ELF class: ELFCLASS64

    安装软件时出现问题   ×.so.×:wrong ELF class: ELFCLASS64 ,大致的意思是软件是32位的,需要32位的 ×.so.×动态链接库,而系统是64位的所提供的该 动态链接库 ...

  8. spring El

    package com.wisely.heighlight_spring4.ch2.el; import java.io.IOException; import org.apache.commons. ...

  9. 『TensorFlow』张量拼接_调整维度_切片

    1.tf.concat tf.concat的作用主要是将向量按指定维连起来,其余维度不变:而1.0版本以后,函数的用法变成: t1 = [[1, 2, 3], [4, 5, 6]] t2 = [[7, ...

  10. VUE + vue-cli + webpack 创建新项目

    首先记录一下命令. 这是一个睿智新手的笔记. p.s.这是配置好环境以后的命令. ----------------------------------------------- $ npm insta ...