【问题标题】:Concatenating multiple lists in Elixir在 Elixir 中连接多个列表
【发布时间】:2017-01-24 14:31:09
【问题描述】:

我正在学习 Elixir,发现自己不得不将多个列表连接在一起,其中有一个开头、中间和结尾。简化示例:

a = [1,2]
b = [3,4]
c = [5,6]
a ++ b ++ c
> [1, 2, 3, 4, 5, 6]

我在直播中这样做了数千次,并希望对此有所了解。

第 1 部分)

我写了一个函数来处理这个,可能有一些东西可以为我做这个,但我没有看到它。我应该为此使用内置的 Elixir 功能吗?

def append(front, back) when is_list(front) when is_list(back) do
  front
  |> Enum.reverse
  |> Enum.reduce(back, &([&1 | &2]))
end

或者我应该刚刚这样做,随着时间的推移它对我来说会变得更自然?

[1, 2]
|> Enum.reverse 
|> Enum.reduce([3, 4], &([&1 | &2]))
|> Enum.reverse
|> Enum.reduce([5, 6], &([&1 | &2]))

第 2 部分)

我把这些部分放在一起的顺序重要吗?

Way 1:
[1, 2]
|> append([3, 4])
|> append([5, 6])

...
Way 2:
end = append([3, 4], [5, 6])
append([1, 2], end)

中间列表是否会在两种情况下重复使用,因为两者都附加了标头指针?

对此的任何帮助都会很棒,干杯。

【问题讨论】:

    标签: elixir


    【解决方案1】:

    无论您使用哪种方法,您最终都将至少克隆除最后一个之外的所有列表,因为您无法在不克隆的情况下附加到链表。所以如果你知道你想连接列表(即你不能修改你的代码来接受像[a, b, c]这样的嵌套列表),我会建议a ++ b ++ c,因为++是在Erlang的C代码中实现的,应该差不多尽可能快,而且绝对比手动连接 Enum.reverse/1Enum.reduce/3 快。

    这是一个比较 a ++ b ++ ca |> append(b) |> append(c) 的微型微基准:

    defmodule BasicBench do
      use Benchfella
    
      bench "++", [a: gen(), b: gen(), c: gen()] do
        a ++ b ++ c
      end
    
      bench "append", [a: gen(), b: gen(), c: gen()] do
        a |> append(b) |> append(c)
      end
    
      def append(front, back) when is_list(front) when is_list(back) do
        front
        |> Enum.reverse
        |> Enum.reduce(back, &([&1 | &2]))
      end
    
      def gen, do: Enum.to_list(1..1000)
    end
    

    和输出:

    benchma iterations   average time
    ++          100000   10.22 µs/op
    append       20000   75.79 µs/op
    

    【讨论】:

    • 旁注:还有Enum.concat/1的性能略好于手动reduce,但仍然比普通的旧好:erlang.++差5倍。另一方面,Enum.concat 适用于任何可枚举
    猜你喜欢
    • 2016-04-19
    • 2018-09-04
    • 1970-01-01
    • 2012-10-22
    • 2018-05-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-05-08
    相关资源
    最近更新 更多