说你想 XOR
两份名单
list1 = [0,1,0,1]
list2 = [0,1,1,0]
给你一个新的列表,是 [0,0,1,1]
.
或者是 [1,1,0,0]
和 [1,1,1,1,1,0,1,0,1,0]
但只是 XOR
然后将第二个列表中的其余部分复制到新的列表中,这样就可以得到 [0,0,1,1,1,0,1,0,1,0]
.
在Erlang中,你可以使用递归来定义
list_xor([], L) ->
L;
list_xor(L, []) ->
L;
list_xor([H1|T1], [H2|T2]) ->
[H1 bxor H2 | list_xor(T1, T2)].
Elixir版本。
def list_xor([], l),
do: l
def list_xor(l, []),
do: l
def list_xor([h1 | t1], [h2 | t2]),
do: [:erlang.bxor(h1, h2) | list_xor(t1, t2)]
Oneliner,只是出于好奇。
[Stream.concat([1,1,0,0], Stream.cycle([nil])), [1,1,1,1,1,0,1,0,1,0]]
|> Enum.zip()
|> Enum.map(fn {nil, e} -> e; {e1, e2} -> :erlang.bxor(e1, e2) end)
#⇒ [0, 0, 1, 1, 1, 0, 1, 0, 1, 0]
import Bitwise
def xor(list_1, list_2), do: do_xor(list_1, list_2, [])
defp do_xor([], [], results), do: Enum.reverse(results)
defp do_xor([element_1 | tail_1], [], results), do: do_xor(tail_1, [], [element_1 | results])
defp do_xor([], [element_2 | tail_2], results), do: do_xor([], tail_2, [element_2 | results])
defp do_xor([element_1 | tail_1], [element_2 | tail_2], results), do: do_xor(tail_1, tail_2, [element_1 ^^^ element_2 | results])
我们在这里做的是使用模式匹配来检查其中一个列表是否是空列表--如果是,就把当前的 element
从其他名单中的 results
列表。
如果两个列表都包含元素,则使用 Bitwise.^^^/2
来进行XOR比较。
最后,如果两个列表都是空的 ([]
),反过来 results
列表并返回它。
P.S. 请注意,我们是如何在结果列表的前面进行预输入,而不是在后面进行追加(这应该像这样做 new_results = results ++ [element]
),因为Elixir中的列表数据结构是以这样一种方式设置的,即向前面预搜索的速度要快得多(O(1)
),而不是追加到后面(O(N)
).由于我们是在前面追加到了 results
列表,结果的顺序是相反的。这就是为什么我们要做 Enum.reverse/1
在最后一步,把结果放回原来的顺序。
如果您 use Bitwise
以获得 ^^^
操作员,你可以简单地用一个组合来实现这一点。理解力 和 Enum.zip/2
:
use Bitwise
for {x, y} <- Enum.zip([0, 1, 0, 1], [0, 1, 1, 0]), do: x ^^^ y
输出。
[0, 0, 1, 1]
对于不同长度的列表,@choroba的递归例子(已投票)很好。下面是这个例子的一个版本,使用的是 ^^^
运营商。
use Bitwise
defmodule Example do
def list_xor([], l), do: l
def list_xor(l, []), do: l
def list_xor([h1 | t1], [h2 | t2]), do: [h1 ^^^ h2 | list_xor(t1, t2)]
end