如何将项目列表映射到 Erlang 记录
How to map a list of items to an Erlang record
二郎初学者来了!
我有一个元素列表,我想将其中的一些元素映射到具有记录的项目。
List = ["a", "b", "c", "d", "e"].
我还有一条记录定义如下:
-record(a_record, { itemA = "", itemB = ""}).
我想将列表映射到与记录定义相匹配的元组中,这样我最终得到:
#a_record{itemA="A", itemB="B" }.
我正在查看列表模块,但还没有看到干净的解决方案。
感谢您的帮助!
您可以使用 record_info/2 和 list_to_tuple/1:
List = ["a", "b", "c", "d", "e"],
List2 = [string:to_upper(P) || P <- lists:sublist(List, record_info(size, a_record)-1)],
list_to_tuple([a_record | List2]).
如果你能保证列表中的元素与要初始化的记录字段的顺序相同,并且列表的元素数量至少与记录的字段数量相同,则可以应用通过利用记录实际上是元组这一事实,从列表中创建记录的实例有点麻烦。例如,您的 a_record
表示为一个元组,其第一个元素是原子 a_record
,后跟 2 个元素,每个元素对应一个记录字段。
1> List = ["a", "b", "c", "d", "e"].
["a","b","c","d","e"]
2> rd(a_record, { itemA = "", itemB = ""}).
a_record
3> ARecord = list_to_tuple([a_record|lists:sublist(List,size(#a_record{})-1)]).
#a_record{itemA = "a",itemB = "b"}
命令 1 定义了我们的 List
,在命令 2 中,我们使用 shell rd
命令来定义一条记录,就像您问题中的记录一样。命令 3 构建一个新列表,其中记录名称作为头部,字段初始值设定项作为尾部。 size/1
函数为我们提供了记录中的字段数,包括其名称,因此我们从中减去 1,并将结果值用作 List
的子列表的大小,以用于初始化记录字段.然后我们将结果列表传递给 list_to_tuple/1
,如您所见,结果是一个 a_record
实例,用 List
.
中的值初始化
我认为您更安全地进行列表理解并实际从映射中检索与记录中的字段关联的键。您最终可能会得到一条充满未定义字段的记录,但您无需进行任何检查以确保地图与记录的 keys/values 数量相同,也无需关心任何顺序。
RecordType = a_record.
RecordFields = record_info(fields, a_record).
Map = #{a_record_field => <<"a record value">>}.
Record = map_to_record(Map, RecordType, RecordFields).
map_to_record(Map, RecordType, RecordFields) ->
RecordValues = [maps:get(RecordField, Map, undefined) || RecordField <- RecordFields],
AlmostRecord = [RecordType | RecordValues],
list_to_tuple(AlmostRecord).
如果您的映射键是二进制字符串,那么您需要将记录字段列表中的原子转换为二进制字符串。
请务必注意,record_info(fields, RecordType)
不是对 record_info
函数的有效调用。我认为这是因为 record_info
的 return 值是在编译时确定的,因为记录本身的语法糖性质基本上是类型元组,并且运行时调用是无效的。
二郎初学者来了!
我有一个元素列表,我想将其中的一些元素映射到具有记录的项目。
List = ["a", "b", "c", "d", "e"].
我还有一条记录定义如下:
-record(a_record, { itemA = "", itemB = ""}).
我想将列表映射到与记录定义相匹配的元组中,这样我最终得到:
#a_record{itemA="A", itemB="B" }.
我正在查看列表模块,但还没有看到干净的解决方案。
感谢您的帮助!
您可以使用 record_info/2 和 list_to_tuple/1:
List = ["a", "b", "c", "d", "e"],
List2 = [string:to_upper(P) || P <- lists:sublist(List, record_info(size, a_record)-1)],
list_to_tuple([a_record | List2]).
如果你能保证列表中的元素与要初始化的记录字段的顺序相同,并且列表的元素数量至少与记录的字段数量相同,则可以应用通过利用记录实际上是元组这一事实,从列表中创建记录的实例有点麻烦。例如,您的 a_record
表示为一个元组,其第一个元素是原子 a_record
,后跟 2 个元素,每个元素对应一个记录字段。
1> List = ["a", "b", "c", "d", "e"].
["a","b","c","d","e"]
2> rd(a_record, { itemA = "", itemB = ""}).
a_record
3> ARecord = list_to_tuple([a_record|lists:sublist(List,size(#a_record{})-1)]).
#a_record{itemA = "a",itemB = "b"}
命令 1 定义了我们的 List
,在命令 2 中,我们使用 shell rd
命令来定义一条记录,就像您问题中的记录一样。命令 3 构建一个新列表,其中记录名称作为头部,字段初始值设定项作为尾部。 size/1
函数为我们提供了记录中的字段数,包括其名称,因此我们从中减去 1,并将结果值用作 List
的子列表的大小,以用于初始化记录字段.然后我们将结果列表传递给 list_to_tuple/1
,如您所见,结果是一个 a_record
实例,用 List
.
我认为您更安全地进行列表理解并实际从映射中检索与记录中的字段关联的键。您最终可能会得到一条充满未定义字段的记录,但您无需进行任何检查以确保地图与记录的 keys/values 数量相同,也无需关心任何顺序。
RecordType = a_record.
RecordFields = record_info(fields, a_record).
Map = #{a_record_field => <<"a record value">>}.
Record = map_to_record(Map, RecordType, RecordFields).
map_to_record(Map, RecordType, RecordFields) ->
RecordValues = [maps:get(RecordField, Map, undefined) || RecordField <- RecordFields],
AlmostRecord = [RecordType | RecordValues],
list_to_tuple(AlmostRecord).
如果您的映射键是二进制字符串,那么您需要将记录字段列表中的原子转换为二进制字符串。
请务必注意,record_info(fields, RecordType)
不是对 record_info
函数的有效调用。我认为这是因为 record_info
的 return 值是在编译时确定的,因为记录本身的语法糖性质基本上是类型元组,并且运行时调用是无效的。