在将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"}
]
最简单最直接的方法是使用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)