举个例子,假设我有collection很多对{first, second}.使用分组这些对
Enum.group_by(collection, fn {first, second} -> first end)
Run Code Online (Sandbox Code Playgroud)
将导致Map其键由传递的匿名函数确定.它的值是对的集合.但是,我希望它的值包含对的second元素.
一般来说,给定一个可枚举的,我想分组提供一个关键提取器和一个值映射器,以便我可以确定将什么放入生成Map的值中.即,我想要类似的东西
map_group_by(
collection,
fn {_first, second} -> second end,
fn {first, _second} -> first end
)
Run Code Online (Sandbox Code Playgroud)
在collection分组之前将值映射到哪里,而键映射器仍然在原始元素上运行.
标准库中有这样的功能吗?如果没有,最实用的方法是什么?
我知道我可以做点什么
Enum.reduce(
collection,
%{},
fn({key, value}, acc) -> Dict.update(acc, key, [value], &([value | &1])) end
)
Run Code Online (Sandbox Code Playgroud)
但这看起来很笨拙并且[value]先发制人地创建了名单(实际上是真的吗?).有没有更简洁有效的方法?
要回答你的问题,我认为没有本地功能可以做到这一点.
但我会给你我的解决方案(免责声明:我是Elixir的新手).
首先,重要的是要注意,正如您在Elixir Docs中看到的那样,元组列表与键值列表相同:
iex> list = [{:a, 1}, {:b, 2}]
[a: 1, b: 2]
iex> list == [a: 1, b: 2]
true
Run Code Online (Sandbox Code Playgroud)
因此,考虑到这一点,它很容易使用Enum.map它.
这确实让它通过了两次,但它看起来比你拥有的更清洁:
defmodule EnumHelpers do
def map_col(lst) do
lst
|> Enum.group_by(fn {x, _} -> x end)
|> Enum.map(fn {x, y} -> {x, Dict.values y} end)
end
end
IO.inspect EnumHelpers.map_col([a: 2, a: 3, b: 3])
Run Code Online (Sandbox Code Playgroud)
将打印出来:
[a: [3, 2], b: [3]]
Run Code Online (Sandbox Code Playgroud)
编辑:更快的版本:
defmodule EnumHelpers do
defp group_one({key, val}, categories) do
Dict.update(categories, key, [val], &[val|&1])
end
def map_col_fast(coll) do
Enum.reduce(coll, %{}, &group_one/2)
end
end
IO.inspect EnumHelpers.map_col_fast([a: 2, a: 3, b: 3])
Run Code Online (Sandbox Code Playgroud)
从Elixir 1.3开始,现在Enum.group_by/3有一个mapper_fun参数,它解决了这个问题.
过时的答案:
此时,标准库中没有这样的功能.我最终使用了这个:
Enum.group_by(enumerable, &elem(&1, 0), &elem(&1, 1))
Run Code Online (Sandbox Code Playgroud)
然后可以这样调用(对于我的例子):
def map_group_by(enumerable, value_mapper, key_extractor) do
Enum.reduce(Enum.reverse(enumerable), %{}, fn(entry, categories) ->
value = value_mapper.(entry)
Map.update(categories, key_extractor.(entry), [value], &[value | &1])
end)
end
Run Code Online (Sandbox Code Playgroud)
它改编自标准库Enum.group_by.关于[value]:我不知道编译器可以或不能优化什么,但至少这也是这样Enum.group_by做的.
请注意该Enum.reverse调用,这不是我的问题中的示例.这可确保元素顺序保留在结果值列表中.如果您不需要保留该顺序(就像我在我的情况下所做的那样,我只想从结果中取样),它可以被删除.
| 归档时间: |
|
| 查看次数: |
4408 次 |
| 最近记录: |