Elixir 基于结构类型改变的分块列表

Elixir 基于结构类型改变的分块列表,elixir,Elixir,我有一个列表,我想根据从结构类型B到a的转换进行分块。例如,我有以下内容: iex(1)> defmodule A, do: defstruct [] {:module, A ... iex(2)> defmodule B, do: defstruct [] {:module, B ... iex(3)> values = [ %A{}, %A{}, %B{}, %B{}, %B{}, %A{}, %A{}, %B{} ] [%A{}, %A{}, %B{}, %B{}, %B

我有一个列表,我想根据从结构类型B到a的转换进行分块。例如,我有以下内容:

iex(1)> defmodule A, do: defstruct []
{:module, A ...
iex(2)> defmodule B, do: defstruct []
{:module, B ...
iex(3)> values = [ %A{}, %A{}, %B{}, %B{}, %B{}, %A{}, %A{}, %B{} ]
[%A{}, %A{}, %B{}, %B{}, %B{}, %A{}, %A{}, %B{}]
我希望将这些数据分为两个元素的列表,其中包含:

[ [ %A{}, %A{}, %B{}, %B{}, %B{} ], [ %A{}, %A{}, %B{} ] ]
如果输入最初是全部A或全部B,则输出将保持不变,因为没有发生B->A转换

我想,
Enum.chunk\u by/2
是一个不错的选择,但我很难弄清楚如何维护前一个元素的上下文,以便知道何时拆分


像这样的问题的惯用解决方案是什么样子的?

Enum.chunk\u by/2
目前不提供对上一个元素的访问,因此在本例中不能使用
Enum.chunk\u by/2
。我们将不得不退回到
reduce/3

在所有的
Enum
函数中,
reduce/3
是最灵活的,大多数
Enum
函数(如果不是全部的话)都在内部使用

下面是一种生成所需输出的方法,给定值
[%A{}、%A{}、%B{}、%B{}、%B{}、%A{}、%A{}、%A{}、%B{}]

  values
  |> Enum.reduce([[]], fn (elem, acc) ->
    prev_list = List.first(acc)         
    prev_elem = List.first(prev_list)
    b_changed_to_a? = fn -> prev_elem.__struct__ == B && elem.__struct__ == A end

    if is_nil(prev_elem) || !b_changed_to_a?.() do
      List.replace_at(acc, 0, [elem|prev_list])
    else
      [[elem]|acc]      
    end
  end)
  |> Enum.map(&Enum.reverse/1)
  |> Enum.reverse
请注意,我总是在列表的前面加上一个元素。这是因为在Elixir中添加列表是一项昂贵的操作


希望这个解决方案有帮助

另一种替代方法是按结构类型chunk_,然后执行另一个过程合并列表(除非列表包含
%B{}
):


另一种方法是使用纯递归:

def collect_chunks([]), do: []
def collect_chunks(list) do
  {chunk, post_chunk} = collect_chunk(list)
  [chunk | collect_chunks(post_chunk)]
end

defp collect_chunk([]), do: {[], []}
defp collect_chunk([%B{} = last_element | [%A{} | _] = post_chunk]), do: {[last_element], post_chunk}
defp collect_chunk([el | rest]) do
  {remaining_chunk, post_chunk} = collect_chunk(rest)
  {[el | remaining_chunk], post_chunk}
end

必须选择这一个,因为它是唯一一个我觉得能够保持鉴于我目前的长生不老药知识水平!谢谢
def collect_chunks([]), do: []
def collect_chunks(list) do
  {chunk, post_chunk} = collect_chunk(list)
  [chunk | collect_chunks(post_chunk)]
end

defp collect_chunk([]), do: {[], []}
defp collect_chunk([%B{} = last_element | [%A{} | _] = post_chunk]), do: {[last_element], post_chunk}
defp collect_chunk([el | rest]) do
  {remaining_chunk, post_chunk} = collect_chunk(rest)
  {[el | remaining_chunk], post_chunk}
end