如何在Elixir / Erlang中引用上一个元素进行枚举

查尔斯·奥克瓦格武

在应用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"}
]
阿列克谢·马蒂什金(Alexei Matiushkin)

最简单,最直接的方法就是使用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)

这样,输出既已调整又已分块

编辑:解决方案的页码:实际测试数据

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)

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章