首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >将命令式算法转化为Elixir

将命令式算法转化为Elixir
EN

Stack Overflow用户
提问于 2022-03-11 09:54:38
回答 3查看 118关注 0票数 1

我在python中有一个算法,需要用函数式编程语言Elixir来实现。

输入:

元组列表:[("A", "B"), ("B", "C"), ..., ("E", "F")]

  • list of booleans:[False, True, True, False, True]
  • 指示元组是否有效,("B", "C")无效,...

输出:

  • [["A"], ["B", "C", "D"], ["E", "F"]]
    • 嵌套的分组tokens
    • A列表没有连接->单个item
    • B, C, D有连接->分组together

基本上,我想将这个python示例代码翻译成Elixir:

代码语言:javascript
运行
复制
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

解决这个问题的灵丹妙药是什么?

EN

回答 3

Stack Overflow用户

发布于 2022-03-11 11:10:59

这是确切的音译。也许有一个更好的方法来做这件事,也许我会回来,如果没有其他人这样做。

代码语言:javascript
运行
复制
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

输出:

代码语言:javascript
运行
复制
[["A"], ["B", "C", "D"], ["E", "F"]]
票数 2
EN

Stack Overflow用户

发布于 2022-03-12 07:36:53

类似的解决方案,使用Enum.chunk_while/4

代码语言:javascript
运行
复制
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函数;您可以这样运行它:

代码语言:javascript
运行
复制
list = ["A", "B", "C", "D", "E", "F"]
acceptance = [false, true, true, false, true]

Chunky.collect(list, acceptance)

在上面的示例中,我没有这样做,因为考虑到列表的大小,增加的开销不值得,但是对于较大的列表,您可能会发现用它们的Enum.xyz等效项替换Stream.xyz函数是有用的。

票数 2
EN

Stack Overflow用户

发布于 2022-04-08 08:43:17

经过更多的药物培训后,我想出了自己的解决方案,避免了匿名函数,并使用了尾递归:

代码语言:javascript
运行
复制
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)
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/71436673

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档