我在python中有一个算法,需要用函数式编程语言Elixir来实现。
输入:
元组列表:[("A", "B"), ("B", "C"), ..., ("E", "F")]
[False, True, True, False, True]
("B", "C")
无效,...输出:
[["A"], ["B", "C", "D"], ["E", "F"]]
A
列表没有连接->单个itemB, C, D
有连接->分组together基本上,我想将这个python示例代码翻译成Elixir:
input = ["A", "B", "C", "D", "E", "F"]
tuples = list(zip(input, input[1:]))
# --> [("A", "B"), ("B", "C"), ..., ("E", "F")]
# this is a black box -> database result
results = [False, True, True, False, True]
[first_item, *_] = input
biglist = []; smalllist = [first_item]
for (left, right), result in zip(tuples, results):
if result:
# valid tuple, keep filling current bucket
smalllist.append(right)
else:
# invalid tuple
biglist.append(smalllist)
smalllist = [right]
if len(smalllist) > 0:
biglist.append(smalllist)
print(biglist)
[["A"], ["B", "C", "D"], ["E", "F"]]
# fls, tru, tru, fls, tru
解决这个问题的灵丹妙药是什么?
发布于 2022-03-11 11:10:59
这是确切的音译。也许有一个更好的方法来做这件事,也许我会回来,如果没有其他人这样做。
defmodule Example do
def run do
input = ~w(A B C D E F)
tuples = Enum.zip(input, tl(input))
results = [false, true, true, false, true]
combined = Enum.zip(tuples, results)
first_item = hd(input)
small_list = [first_item]
big_list = []
{small_list, big_list} =
Enum.reduce(combined, {small_list, big_list}, fn
{{_left, right}, true}, {small_list, big_list} ->
{[right | small_list], big_list}
{{_left, right}, false}, {small_list, big_list} ->
{[right], [Enum.reverse(small_list) | big_list]}
end)
case small_list do
[] -> big_list
_ -> [Enum.reverse(small_list) | big_list]
end
|> Enum.reverse()
end
end
输出:
[["A"], ["B", "C", "D"], ["E", "F"]]
发布于 2022-03-12 07:36:53
类似的解决方案,使用Enum.chunk_while/4
defmodule Chunky do
def collect([], _), do: []
def collect([hd | rest], acceptance_list) do
rest
|> Enum.zip(acceptance_list)
|> Enum.chunk_while(
[hd],
fn
{next, true}, candidate_list ->
{:cont, [next | candidate_list]}
{next, false}, candidate_list ->
{:cont, Enum.reverse(candidate_list), [next]}
end,
fn
[] = acc -> {:cont, acc}
[_ | _] = candidate_list -> {:cont, Enum.reverse(candidate_list), []}
end
)
end
end
我跳过了第一个zip,因为它的值被忽略了(错过了前几个压缩)。
在chunk_while中的第一个模式匹配情况下,如果先前的接受是错误的,我们将子列表替换为"next“项,并发出反向块。
对于第二种情况,如果先前的接受是错误的,我们将子列表替换为"next“项,并发出反向块。
对这种方法的一个小警告是,在幕后,chunk_while或多或少地做了Adam的解决方案:它反转了每个块的列表。因此,实际上,这需要在幕后进行额外的反转,这与数据大小无关,但可能会引起更大列表的关注。
尽管有可能,它会要求稍微少一点的认知负荷。
为了便于测试,我将其转换为/2
函数;您可以这样运行它:
list = ["A", "B", "C", "D", "E", "F"]
acceptance = [false, true, true, false, true]
Chunky.collect(list, acceptance)
在上面的示例中,我没有这样做,因为考虑到列表的大小,增加的开销不值得,但是对于较大的列表,您可能会发现用它们的Enum.xyz
等效项替换Stream.xyz
函数是有用的。
发布于 2022-04-08 08:43:17
经过更多的药物培训后,我想出了自己的解决方案,避免了匿名函数,并使用了尾递归:
tokens = ["A", "B", "C", "D", "E", "F"]
connections = [false, true, true, true, true]
defmodule Builder do
def run(tokens, conns) do
# use the first token as group
{:ok, groups} = group(tl(tokens), conns, [hd(tokens)], [])
Enum.reverse(groups)
end
# no more tokens and conns -> all good
defp group([], [], group, all_groups), do: {:ok, [Enum.reverse(group) | all_groups]}
# something is wrong, unequal amount of tokens and conns
defp group(_, [], _, _), do: {:error, "too many tokens"}
defp group([], _, _, _), do: {:error, "too many conns"}
# process tokens with tail recursion
defp group([t | tokens], [valid_connection | conns], group, all_groups) do
if valid_connection do
# add token to current group
group(tokens, conns, [t | group], all_groups)
else
# add group to final list and start new group
group(tokens, conns, [t], [Enum.reverse(group) | all_groups])
end
end
end
Builder.run(tokens, connections)
https://stackoverflow.com/questions/71436673
复制相似问题