【问题标题】:How to map a list of items to an Erlang record如何将项目列表映射到 Erlang 记录
【发布时间】:2016-01-20 08:42:16
【问题描述】:

这里是 Erlang 初学者!

我有一个元素列表,我想将其中的一些元素映射到带有记录的项目。

List = ["a", "b", "c", "d", "e"].

我还有一条记录定义如下:

-record(a_record, { itemA = "", itemB = ""}).

我想将列表映射到与记录定义匹配的元组中,以便最终得到:

#a_record{itemA="A", itemB="B" }.

我正在查看列表模块,但还没有找到干净的解决方案。

感谢您的帮助!

【问题讨论】:

    标签: erlang


    【解决方案1】:

    如果您可以保证列表中的元素与要初始化的记录字段的顺序相同,并且列表中的元素数量至少与记录中的字段数量相同,则可以应用一点通过利用记录是隐藏的元组这一事实,从列表中创建记录实例的黑客攻击。例如,您的 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,如您所见,结果是使用List 中的值初始化的a_record 实例。

    【讨论】:

    • 另请注意,尽管从技术上讲这是您的做法,但最好通过对字段进行硬编码并从列表中获取每个值来手动执行此操作。这样,当记录长度或字段顺序发生变化时,您最终不会创建无效记录。
    • @AdamLindberg 您的建议对我来说似乎也是一种安全的方法。当您说手动时,您的意思是使用诸如 lists:nth 之类的东西将每个项目从列表中拉出,然后从中构建记录吗?
    • @BrianB:另一件事:虽然记录和地图不可互换,但您可能会考虑地图是否适合您的用例,如果适合,请使用maps:from_list/1,但请注意,您'在这种情况下需要一个键值对列表。
    • @BrianB,手动就像[A, B | _] = List, #a_record{itemA =A, itemB =B}
    【解决方案2】:

    你可以使用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]).
    

    【讨论】:

      【解决方案3】:

      我认为执行列表理解并实际从映射中检索与记录中的字段相关联的键会更安全。您最终可能会得到一个充满未定义字段的记录,但您无需进行任何检查以确保映射与记录具有相同数量的键/值,也无需担心任何顺序。

      
      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 的返回值是在编译时确定的,因为记录本身的语法糖性质基本上是类型化的元组,并且运行时调用是无效的。

      【讨论】:

        猜你喜欢
        • 2011-06-24
        • 1970-01-01
        • 2021-05-14
        • 1970-01-01
        • 2020-04-18
        • 2021-01-22
        • 1970-01-01
        • 2021-01-04
        • 2014-07-21
        相关资源
        最近更新 更多