如何枚举Elixir / Erlang中对前一个元素的引用

问题描述 投票:1回答:1

在将Enum.chunk_by应用到列表之前,我需要规范化元素列表。

通常,当我们枚举时,我们逐个项目,例如

source_list |> normalize_item

我们如何在引用列表中的前一个元素时枚举?

另外,我们如何在下一次迭代中保留对最后一个normalized_item的引用?

样本数据:

[
%PhoneBills.Text{end: 91, page: 13, row: 237, start: 48, text: "2348035250601"},
%PhoneBills.Text{end: 155, page: 13, row: 237, start: 99, text: "17-12-2014 10:08:32"},
%PhoneBills.Text{end: 247, page: 13, row: 238, start: 168, text: "1080643204171320 2811630"},
%PhoneBills.Text{end: 286, page: 13, row: 238, start: 268, text: "400.00"},
%PhoneBills.Text{end: 394, page: 13, row: 238, start: 370, text: "Payment"},
%PhoneBills.Text{end: 91, page: 13, row: 244, start: 48, text: "2348035250601"},
%PhoneBills.Text{end: 155, page: 13, row: 244, start: 99, text: "17-12-2014 10:09:12"},
%PhoneBills.Text{end: 247, page: 13, row: 246, start: 168, text: "1775292204171752 2811630"},
%PhoneBills.Text{end: 286, page: 13, row: 246, start: 268, text: "400.00"},
%PhoneBills.Text{end: 394, page: 13, row: 246, start: 370, text: "Payment"},
%PhoneBills.Text{end: 91, page: 13, row: 252, start: 48, text: "2348068014410"},
%PhoneBills.Text{end: 155, page: 13, row: 252, start: 99, text: "17-12-2014 08:34:23"},
%PhoneBills.Text{end: 250, page: 13, row: 254, start: 168, text: "174729900817063 100153465"},
%PhoneBills.Text{end: 286, page: 13, row: 254, start: 263, text: "1,500.00"},
%PhoneBills.Text{end: 394, page: 13, row: 254, start: 370, text: "Payment"}
]

我需要规范化上面的row字段,其中两个相邻元素实际上在同一行,如果它们的差异是<= 2,则在将Enum.chunk_by应用于列表之前

我考虑过Enum.chunk_while但在这种情况下它没有提供一个好的解决方案。

预期产量:

[
%PhoneBills.Text{end: 91, page: 13, row: 237, start: 48, text: "2348035250601"},
%PhoneBills.Text{end: 155, page: 13, row: 237, start: 99, text: "17-12-2014 10:08:32"},
%PhoneBills.Text{end: 247, page: 13, row: 237, start: 168, text: "1080643204171320 2811630"},
%PhoneBills.Text{end: 286, page: 13, row: 237, start: 268, text: "400.00"},
%PhoneBills.Text{end: 394, page: 13, row: 237, start: 370, text: "Payment"},
%PhoneBills.Text{end: 91, page: 13, row: 244, start: 48, text: "2348035250601"},
%PhoneBills.Text{end: 155, page: 13, row: 244, start: 99, text: "17-12-2014 10:09:12"},
%PhoneBills.Text{end: 247, page: 13, row: 244, start: 168, text: "1775292204171752 2811630"},
%PhoneBills.Text{end: 286, page: 13, row: 244, start: 268, text: "400.00"},
%PhoneBills.Text{end: 394, page: 13, row: 244, start: 370, text: "Payment"},
%PhoneBills.Text{end: 91, page: 13, row: 252, start: 48, text: "2348068014410"},
%PhoneBills.Text{end: 155, page: 13, row: 252, start: 99, text: "17-12-2014 08:34:23"},
%PhoneBills.Text{end: 250, page: 13, row: 252, start: 168, text: "174729900817063 100153465"},
%PhoneBills.Text{end: 286, page: 13, row: 252, start: 263, text: "1,500.00"},
%PhoneBills.Text{end: 394, page: 13, row: 252, start: 370, text: "Payment"}
]
elixir enumeration
1个回答
3
投票

最简单最直接的方法是使用Enum.reduce/3。不幸的是,我无法解析你想要如何改变row的要求,但这是一个通用的例子:

Enum.reduce(source_list, %{last: nil, values: []}, fn e, acc ->
  %{last: e, values: acc.values ++ [e]}
end)

此外,Enum.chunk_while/4也是一个很好的候选人。如果你能产生预期的输出,我可能会举出一个chunk_while应用程序的例子。


defmodule PhoneBills.Text,
  do: defstruct ~w|end page row start text|a

input = [...]

Enum.reduce(input, %{row: 0, acc: []}, fn e, acc ->        
  row = if e.row - acc.row <= 2, do: acc.row, else: e.row    
  %{row: row, acc: acc.acc ++ [%PhoneBills.Text{e | row: row}]}
end)

Enum.chunk_while/4的解决方案:

chunk_fun = fn
  e, %{row: 0, acc: acc} -> # init
    {:cont, %{acc: [e], row: e.row}}
  %{row: e_row} = e, %{row: row, acc: acc} when e_row - row > 2 -> # emit
    {:cont, acc, %{row: e_row, acc: [e]}}
  e, %{row: row, acc: acc} -> # continue collecting
    {:cont, %{row: row, acc: acc ++ [%PhoneBills.Text{e | row: row}]}}
end

after_fun = fn
  %{acc: []} -> {:cont, []}
  %{acc: acc} -> {:cont, acc, []}
end

Enum.chunk_while(input, %{row: 0, acc: []}, chunk_fun, after_fun)

这样,输出已经被调整和分块。

编辑:解决页码的解决方案:actual test data

chunk_fun = fn
  # init
  e, %{page: 0, row: 0, acc: acc} ->
    {:cont, %{acc: [e], page: e.page, row: e.row}}

   # emit - while on same page, or on different page
  %{row: e_row, page: e_page} = e, %{page: page, row: row, acc: acc}
  when e_page == page and e_row - row > 2 or e_page != page ->
    {:cont, acc, %{page: e_page, row: e_row, acc: [e]}}

  # continue collecting
  e, %{page: page, row: row, acc: acc} ->
    {:cont, %{page: page, row: row, acc: acc ++ [%Text{e | row: row, page: page}]}}
end

after_fun = fn
  %{acc: []} -> {:cont, []}
  %{acc: acc} -> {:cont, acc, []}
end

Enum.chunk_while(input, %{row: 0, page: 0, acc: []}, chunk_fun, after_fun)
© www.soinside.com 2019 - 2024. All rights reserved.