Elixir map_reduce引用最后一个元素

时间:2018-02-18 15:17:42

标签: recursion elixir

在与列表中的最后一个元素进行比较时,如何循环(递归或使用reduceListMap

例如,假设我有一个这样的地图列表:

    datetime = Timex.beginning_of_day(Timex.now)
    data = [%{a: 0, cluster: 0, time: datetime},
            %{a: 1, cluster: 0, time: Timex.shift(datetime, minutes: 3)},
            %{a: 2, cluster: 0, time: Timex.shift(datetime, minutes: 6)},
            %{a: 3, cluster: 0, time: Timex.shift(datetime, minutes: 9)},
            %{a: 4, cluster: 1, time: Timex.shift(datetime, minutes: 12)},
            %{a: 5, cluster: 1, time: Timex.shift(datetime, minutes: 15)},
            %{a: 6, cluster: 0, time: Timex.shift(datetime, minutes: 18)},
            %{a: 7, cluster: 0, time: Timex.shift(datetime, minutes: 21)},
            %{a: 8, cluster: 0, time: Timex.shift(datetime, minutes: 23)},
            %{a: 9, cluster: 2, time: Timex.shift(datetime, minutes: 26)},
            %{a: 10, cluster: 2, time: Timex.shift(datetime, minutes: 29)},
            %{a: 11, cluster: 2, time: Timex.shift(datetime, minutes: 32)},
            %{a: 12, cluster: 1, time: Timex.shift(datetime, minutes: 35)},
            %{a: 13, cluster: 1, time: Timex.shift(datetime, minutes: 38)}]

我想修改每个地图的cluster属性,以表示它所处的组所在的组。

如果group_by ID不重复,则使用cluster非常有用。

我想在他们改变组时对它们进行分组,结果是这样的:

            [%{a: 0, cluster: 0, time: datetime},
            %{a: 1, cluster: 0, time: Timex.shift(datetime, minutes: 3)},
            %{a: 2, cluster: 0, time: Timex.shift(datetime, minutes: 6)},
            %{a: 3, cluster: 0, time: Timex.shift(datetime, minutes: 9)},
            %{a: 4, cluster: 1, time: Timex.shift(datetime, minutes: 12)},
            %{a: 5, cluster: 1, time: Timex.shift(datetime, minutes: 15)},
            %{a: 6, cluster: 2, time: Timex.shift(datetime, minutes: 18)},
            %{a: 7, cluster: 2, time: Timex.shift(datetime, minutes: 21)},
            %{a: 8, cluster: 2, time: Timex.shift(datetime, minutes: 23)},
            %{a: 9, cluster: 3, time: Timex.shift(datetime, minutes: 26)},
            %{a: 10, cluster: 3, time: Timex.shift(datetime, minutes: 29)},
            %{a: 11, cluster: 3, time: Timex.shift(datetime, minutes: 32)},
            %{a: 12, cluster: 4, time: Timex.shift(datetime, minutes: 35)},
            %{a: 13, cluster: 4, time: Timex.shift(datetime, minutes: 38)}]

为此,我需要将列表中的当前项与前一项进行比较。我已经开始使用这样的东西(下面)并停止,因为我知道它不会引用前一项来比较当前项目与前一项目:

Enum.map_reduce(data, 0, fn(x, acc) -> cluster_grouping(x, acc) end)

  def cluster_grouping(x, acc) do
    cond do
      x.cluster == acc -> {Map.put(x, :cluster, acc), acc}
      x.cluster > acc -> {Map.put(x, :cluster, acc), acc + 1}
    end
  end

2 个答案:

答案 0 :(得分:1)

您需要在累加器中保留两个整数:当前生成的集群(每次更改时将增加1)和集群的最后一个原始值。

datetime = Timex.beginning_of_day(Timex.now)
data = [%{a: 0, cluster: 0, time: datetime},
        %{a: 1, cluster: 0, time: Timex.shift(datetime, minutes: 3)},
        %{a: 2, cluster: 0, time: Timex.shift(datetime, minutes: 6)},
        %{a: 3, cluster: 0, time: Timex.shift(datetime, minutes: 9)},
        %{a: 4, cluster: 1, time: Timex.shift(datetime, minutes: 12)},
        %{a: 5, cluster: 1, time: Timex.shift(datetime, minutes: 15)},
        %{a: 6, cluster: 0, time: Timex.shift(datetime, minutes: 18)},
        %{a: 7, cluster: 0, time: Timex.shift(datetime, minutes: 21)},
        %{a: 8, cluster: 0, time: Timex.shift(datetime, minutes: 23)},
        %{a: 9, cluster: 2, time: Timex.shift(datetime, minutes: 26)},
        %{a: 10, cluster: 2, time: Timex.shift(datetime, minutes: 29)},
        %{a: 11, cluster: 2, time: Timex.shift(datetime, minutes: 32)},
        %{a: 12, cluster: 1, time: Timex.shift(datetime, minutes: 35)},
        %{a: 13, cluster: 1, time: Timex.shift(datetime, minutes: 38)}]

Enum.map_reduce(data, {0, 0}, fn x, {i, last} -> 
  i = if x.cluster == last, do: i, else: i + 1
  {Map.put(x, :cluster, i), {i, x.cluster}}
end)
|> elem(0)
|> IO.inspect

输出:

[
  %{a: 0, cluster: 0, time: #DateTime<2018-02-18 00:00:00Z>},
  %{a: 1, cluster: 0, time: #DateTime<2018-02-18 00:03:00Z>},
  %{a: 2, cluster: 0, time: #DateTime<2018-02-18 00:06:00Z>},
  %{a: 3, cluster: 0, time: #DateTime<2018-02-18 00:09:00Z>},
  %{a: 4, cluster: 1, time: #DateTime<2018-02-18 00:12:00Z>},
  %{a: 5, cluster: 1, time: #DateTime<2018-02-18 00:15:00Z>},
  %{a: 6, cluster: 2, time: #DateTime<2018-02-18 00:18:00Z>},
  %{a: 7, cluster: 2, time: #DateTime<2018-02-18 00:21:00Z>},
  %{a: 8, cluster: 2, time: #DateTime<2018-02-18 00:23:00Z>},
  %{a: 9, cluster: 3, time: #DateTime<2018-02-18 00:26:00Z>},
  %{a: 10, cluster: 3, time: #DateTime<2018-02-18 00:29:00Z>},
  %{a: 11, cluster: 3, time: #DateTime<2018-02-18 00:32:00Z>},
  %{a: 12, cluster: 4, time: #DateTime<2018-02-18 00:35:00Z>},
  %{a: 13, cluster: 4, time: #DateTime<2018-02-18 00:38:00Z>}
]

答案 1 :(得分:0)

更多的elixirish方法是在map-reducer中的函数子句上使用模式匹配:

Enum.map_reduce(data, {0, 0}, fn
  %{cluster: last} = x, {i, last} ->
    {%{x | cluster: i}, {i, last}}
  %{cluster: last} = x, {i, _} ->
    {%{x | cluster: i + 1}, {i + 1, last}}
end)