元组列表[{id,[< List>]},{id2,[< List>]}]其中id是原始列表元组的第二项-Erlang [英] List of tuples [{id, [<List>]}, {id2, [<List>]} ] where ids are the second item of the tuple of the original list- Erlang

查看:104
本文介绍了元组列表[{id,[< List>]},{id2,[< List>]}]其中id是原始列表元组的第二项-Erlang的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

标题^有点令人困惑,但我会举例说明我想要实现的目标:

The title^ is kinda confusing but I will illustrate what I want to achieve:

我有:

[{<<"5b71d7e458c37fa04a7ce768">>,<<"5b3f77502dfe0deeb8912b42">>,<<"1538077790705827">>},
     {<<"5b71d7e458c37fa04a7ce768">>,<<"5b3f77502dfe0deeb8912b42">>,<<"1538078530667847">>},
     {<<"5b71d7e458c37fa04a7ce768">>,<<"5b3f77502dfe0deeb8912b42">>,<<"1538077778390908">>},
     {<<"5b71d7e458c37fa04a7ce768">>,<<"5bad45b1e990057961313822">>,<<"1538082492283531">>
}]

我想将其转换为这样的列表:

I want to convert it to a list like this:

[ 
{<<"5b3f77502dfe0deeb8912b42">>,
   [{<<"5b71d7e458c37fa04a7ce768">>,<<"5b3f77502dfe0deeb8912b42">>,<<"1538077790705827">>},
    {<<"5b71d7e458c37fa04a7ce768">>,<<"5b3f77502dfe0deeb8912b42">>,<<"1538078530667847">>},
    {<<"5b71d7e458c37fa04a7ce768">>,<<"5b3f77502dfe0deeb8912b42">>,<<"1538077778390908">>}
   ]},

{<<"5bad45b1e990057961313822">>,
   [{<<"5b71d7e458c37fa04a7ce768">>,<<"5bad45b1e990057961313822">>,<<"1538082492283531">>}
   ]}
]

元组列表 [{id,[< List>]},{id2,[< ; List>]}] 其中id是原始列表元组的第二项

List of tuples [{id, [<List>]}, {id2, [<List>]} ] where ids are the second item of the tuple of the original list

示例:

& lt;< 5b71d7e458c37fa04a7ce768 >>,<< 5b3f77502dfe0deeb8912b42 >> ,< 1538077790705827 >>

<<"5b71d7e458c37fa04a7ce768">>,<<"5b3f77502dfe0deeb8912b42">>,<<"1538077790705827">>

推荐答案

我想我明白您的要求了...如果我错了,请纠正我。

I think I see what you're after... Please correct me if I'm wrong.

有一个这样做的方法很多,实际上仅取决于您有兴趣使用哪种数据结构来检查like-keys。我将向您展示两种根本不同的方法以及最近可用的第三种混合方法:

There are a number of ways to do this, it really just depends on what sort of data structure you're interested in using to check the presence of like-keys. I'll show you two fundamentally different ways to do this and a third hybrid method that has become recently available:


  • 索引数据类型(在在这种情况下地图

  • 列表操作与匹配

  • 地图键上的混合匹配

由于您是新手,我将使用第一种情况来演示两种书写方式:显式递归和使用列表模块中的实际列表功能

Since you're new I'll use the first case to demonstrate two ways of writing it: explicit recursion and using an actual list function from the lists module.

索引数据类型

我们要做的第一种方法是使用哈希表(又名 dict , map, hash, K / V等),并显式地遍历元素,检查遇到的密钥是否存在,如果密钥不正确,则将其添加唱,或附加到它指向的值列表。为此,我们将使用Erlang地图。在功能结束时,我们会将实用程序映射转换回列表:

The first way we'll do this is to use a hash table (aka "dict", "map", "hash", "K/V", etc.) and explicitly recurse through the elements, checking for the presence of the key encountered and adding it if it is missing, or appending to the list of values it points to if it does. We'll use an Erlang map for this. At the end of the function we'll convert the utility map back to a list:

explicit_convert(List) ->
    Map = explicit_convert(List, maps:new()),
    maps:to_list(Map).

explicit_convert([H | T], A) ->
    K = element(2, H),
    NewA =
        case maps:is_key(K, A) of
            true ->
                V = maps:get(K, A),
                maps:put(K, [H | V], A);
            false ->
                maps:put(K, [H], A)
        end,
    explicit_convert(T, NewA);
explicit_convert([], A) ->
    A.

显式递归没有什么问题(如果您这样做,是新的,因为它的每个部分都保留在公开位置以供检查),但这是左折,我们已经有了一个库函数,可以抽象出一些管道。因此,我们实际上只需要编写一个检查元素是否存在并添加键或附加值的函数即可:

There is nothing wrong with explicit recursion (it is particularly good if you're new, because every part of it is left in the open to be examined), but this is a "left fold" and we already have a library function that abstracts a little bit of the plumbing out. So we really only need to write a function that checks for the presence of an element, and adds the key or appends the value:

fun_convert(List) ->
    Map = lists:foldl(fun convert/2, maps:new(), List),
    maps:to_list(Map).

convert(H, A) ->
    K = element(2, H),
    case maps:is_key(K, A) of
        true ->
            V = maps:get(K, A),
            maps:put(K, [H | V], A);
        false ->
            maps:put(K, [H], A)
    end.

列表转换

我们可以完成此操作的另一种主要方法是使用列表匹配。为此,您需要首先确保您的元素在要用作键的元素上排序,以便可以将其用作工作元素并与之匹配。一旦您凝视了一下,该代码应该很容易理解(也许一旦完全困惑,也许会写出一次如何在纸上手动遍历您的列表):

The other major way we could have done this is with listy matching. To do that you need to first guarantee that your elements are sorted on the element you want to use as a key so that you can use it as a sort of "working element" and match on it. The code should be pretty easy to understand once you stare at it for a bit (maybe write out how it will step through your list by hand on paper once if you're totally perplexed):

listy_convert(List) ->
    [T = {_, K, _} | Rest] = lists:keysort(2, List),
    listy_convert(Rest, {K, [T]}, []).

listy_convert([T = {_, K, _} | Rest], {K, Ts}, Acc) ->
    listy_convert(Rest, {K, [T | Ts]}, Acc);
listy_convert([T = {_, K, _} | Rest], Done, Acc) ->
    listy_convert(Rest, {K, [T]}, [Done | Acc]);
listy_convert([], Done, Acc) ->
    [Done | Acc].

请注意,我们在对列表进行排序后立即对其进行了拆分。原因是我们可以启动泵,可以这么说,在我们第一次调用 listy_convert / 3 时。这也意味着如果您向其传递一个空列表,该函数将崩溃。您可以通过在 listy_convert / 1 中添加与空列表 [] 匹配的子句来解决该问题。

Note that we split the list immediately after sorting it. The reason is that we have "prime the pump", so to speak, on the first call we make to listy_convert/3. This also means that this function will crash if you pass it an empty list. You can solve that by adding a clause to listy_convert/1 that matches on the empty list [].

最后一点魔术

牢记这些……考虑到我们由于适用于地图的神奇语法,在较新版本的Erlang中也提供了一些混合选项。我们可以在 case 子句内匹配(大多数值)映射键(尽管我们不能统一函数头中其他参数提供的键值): / p>

With those firmly in mind... consider that we also have a bit of a hybrid option available in newer versions of Erlang due to the magical syntax available to maps. We can match (most values) on map keys inside of a case clause (though we can't unify on a key value provided by other arguments within a function head):

map_convert(List) ->
    maps:to_list(map_convert(List, #{})).

map_convert([T = {_, K, _} | Rest], Acc) ->
    case Acc of
        #{K := Ts} -> map_convert(Rest, Acc#{K := [T | Ts]});
        _          -> map_convert(Rest, Acc#{K => [T]})
    end;
map_convert([], Acc) ->
    Acc.

这篇关于元组列表[{id,[&lt; List&gt;]},{id2,[&lt; List&gt;]}]其中id是原始列表元组的第二项-Erlang的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆