查看源代码 枚举速查表

快速参考 Enum 模块,用于操作集合(称为可枚举)。以下大多数示例使用以下数据结构

cart = [
  %{fruit: "apple", count: 3},
  %{fruit: "banana", count: 1},
  %{fruit: "orange", count: 6}
]

一些示例使用 string =~ part 运算符,它检查左边的字符串是否包含右边的部分。

谓词

any?(enum, fun)

iex> Enum.any?(cart, & &1.fruit == "orange")
true
iex> Enum.any?(cart, & &1.fruit == "pear")
false

any? 在空集合上始终为 false

iex> Enum.any?([], & &1.fruit == "orange")
false

all?(enum, fun)

iex> Enum.all?(cart, & &1.count > 0)
true
iex> Enum.all?(cart, & &1.count > 1)
false

all? 在空集合上始终为 true

iex> Enum.all?([], & &1.count > 0)
true

member?(enum, value)

iex> Enum.member?(cart, %{fruit: "apple", count: 3})
true
iex> Enum.member?(cart, :something_else)
false

item in enum 等效于 Enum.member?(enum, item)

iex> %{fruit: "apple", count: 3} in cart
true
iex> :something_else in cart
false

empty?(enum)

iex> Enum.empty?(cart)
false
iex> Enum.empty?([])
true

过滤

filter(enum, fun)

iex> Enum.filter(cart, &(&1.fruit =~ "o"))
[%{fruit: "orange", count: 6}]
iex> Enum.filter(cart, &(&1.fruit =~ "e"))
[
  %{fruit: "apple", count: 3},
  %{fruit: "orange", count: 6}
]

reject(enum, fun)

iex> Enum.reject(cart, &(&1.fruit =~ "o"))
[
  %{fruit: "apple", count: 3},
  %{fruit: "banana", count: 1}
]

推导式

过滤也可以使用推导式完成

iex> for item <- cart, item.fruit =~ "e" do
...>   item
...> end
[
  %{fruit: "apple", count: 3},
  %{fruit: "orange", count: 6}
]

推导式中的模式匹配也充当过滤器

iex> for %{count: 1, fruit: fruit} <- cart do
...>   fruit
...> end
["banana"]

映射

map(enum, fun)

iex> Enum.map(cart, & &1.fruit)
["apple", "banana", "orange"]
iex> Enum.map(cart, fn item ->
...>   %{item | count: item.count + 10}
...> end)
[
  %{fruit: "apple", count: 13},
  %{fruit: "banana", count: 11},
  %{fruit: "orange", count: 16}
]

map_every(enum, nth, fun)

iex> Enum.map_every(cart, 2, fn item ->
...>   %{item | count: item.count + 10}
...> end)
[
  %{fruit: "apple", count: 13},
  %{fruit: "banana", count: 1},
  %{fruit: "orange", count: 16}
]

推导式

映射也可以使用推导式完成

iex> for item <- cart do
...>   item.fruit
...> end
["apple", "banana", "orange"]

您也可以同时过滤和映射

iex> for item <- cart, item.fruit =~ "e" do
...>   item.fruit
...> end
["apple", "orange"]

副作用

each(enum, fun)

iex> Enum.each(cart, &IO.puts(&1.fruit))
apple
banana
orange
:ok

Enum.each/2 专门用于副作用。

累积

reduce(enum, acc, fun)

iex> Enum.reduce(cart, 0, fn item, acc ->
...>   item.count + acc
...> end)
10

map_reduce(enum, acc, fun)

iex> Enum.map_reduce(cart, 0, fn item, acc ->
...>   {item.fruit, item.count + acc}
...> end)
{["apple", "banana", "orange"], 10}

scan(enum, acc, fun)

iex> Enum.scan(cart, 0, fn item, acc ->
...>   item.count + acc
...> end)
[3, 4, 10]

reduce_while(enum, acc, fun)

iex> Enum.reduce_while(cart, 0, fn item, acc ->
...>   if item.fruit == "orange" do
...>     {:halt, acc}
...>   else
...>     {:cont, item.count + acc}
...>   end
...> end)
4

推导式

归约也可以使用推导式完成

iex> for item <- cart, reduce: 0 do
...>   acc -> item.count + acc
...> end
10

您也可以同时过滤和归约

iex> for item <- cart, item.fruit =~ "e", reduce: 0 do
...>   acc -> item.count + acc
...> end
9

聚合

count(enum)

iex> Enum.count(cart)
3

参见 Enum.count_until/2 来统计直到限制。

frequencies(enum)

iex> Enum.frequencies(["apple", "banana", "orange", "apple"])
%{"apple" => 2, "banana" => 1, "orange" => 1}

frequencies_by(enum, key_fun)

水果最后一个字母的频率

iex> Enum.frequencies_by(cart, &String.last(&1.fruit))
%{"a" => 1, "e" => 2}

count(enum, fun)

iex> Enum.count(cart, &(&1.fruit =~ "e"))
2
iex> Enum.count(cart, &(&1.fruit =~ "y"))
0

参见 Enum.count_until/3 来统计使用函数直到限制。

sum(enum)

iex> cart |> Enum.map(& &1.count) |> Enum.sum()
10

product(enum)

iex> cart |> Enum.map(& &1.count) |> Enum.product()
18

排序

sort(enum, sorter \\ :asc)

iex> cart |> Enum.map(& &1.fruit) |> Enum.sort()
["apple", "banana", "orange"]
iex> cart |> Enum.map(& &1.fruit) |> Enum.sort(:desc)
["orange", "banana", "apple"]

对结构体进行排序时,请使用 Enum.sort/2 并使用模块作为排序器。

sort_by(enum, mapper, sorter \\ :asc)

iex> Enum.sort_by(cart, & &1.count)
[
  %{fruit: "banana", count: 1},
  %{fruit: "apple", count: 3},
  %{fruit: "orange", count: 6}
]
iex> Enum.sort_by(cart, & &1.count, :desc)
[
  %{fruit: "orange", count: 6},
  %{fruit: "apple", count: 3},
  %{fruit: "banana", count: 1}
]

当排序值是结构体时,请使用 Enum.sort_by/3 并使用模块作为排序器。

min(enum)

iex> cart |> Enum.map(& &1.count) |> Enum.min()
1

比较结构体时,请使用 Enum.min/2 并使用模块作为排序器。

min_by(enum, mapper)

iex> Enum.min_by(cart, & &1.count)
%{fruit: "banana", count: 1}

比较结构体时,请使用 Enum.min_by/3 并使用模块作为排序器。

max(enum)

iex> cart |> Enum.map(& &1.count) |> Enum.max()
6

比较结构体时,请使用 Enum.max/2 并使用模块作为排序器。

max_by(enum, mapper)

iex> Enum.max_by(cart, & &1.count)
%{fruit: "orange", count: 6}

比较结构体时,请使用 Enum.max_by/3 并使用模块作为排序器。

连接 & 展平

concat(enums)

iex> Enum.concat([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
[1, 2, 3, 4, 5, 6, 7, 8, 9]

concat(left, right)

iex> Enum.concat([1, 2, 3], [4, 5, 6])
[1, 2, 3, 4, 5, 6]

flat_map(enum, fun)

iex> Enum.flat_map(cart, fn item ->
...>   List.duplicate(item.fruit, item.count)
...> end)
["apple", "apple", "apple", "banana", "orange",
 "orange", "orange", "orange", "orange", "orange"]

flat_map_reduce(enum, acc, fun)

iex> Enum.flat_map_reduce(cart, 0, fn item, acc ->
...>   list = List.duplicate(item.fruit, item.count)
...>   acc = acc + item.count
...>   {list, acc}
...> end)
{["apple", "apple", "apple", "banana", "orange",
  "orange", "orange", "orange", "orange", "orange"], 10}

推导式

展平也可以使用推导式完成

iex> for item <- cart,
...>     fruit <- List.duplicate(item.fruit, item.count) do
...>   fruit
...> end
["apple", "apple", "apple", "banana", "orange",
 "orange", "orange", "orange", "orange", "orange"]

转换

into(enum, collectable)

iex> pairs = [{"apple", 3}, {"banana", 1}, {"orange", 6}]
iex> Enum.into(pairs, %{})
%{"apple" => 3, "banana" => 1, "orange" => 6}

into(enum, collectable, transform)

iex> Enum.into(cart, %{}, fn item ->
...>   {item.fruit, item.count}
...> end)
%{"apple" => 3, "banana" => 1, "orange" => 6}

to_list(enum)

iex> Enum.to_list(1..5)
[1, 2, 3, 4, 5]

推导式

转换也可以使用推导式完成

iex> for item <- cart, into: %{} do
...>   {item.fruit, item.count}
...> end
%{"apple" => 3, "banana" => 1, "orange" => 6}

重复项 & 唯一项

dedup(enum)

dedup 只删除连续的重复项

iex> Enum.dedup([1, 2, 2, 3, 3, 3, 1, 2, 3])
[1, 2, 3, 1, 2, 3]

dedup_by(enum, fun)

根据属性删除连续的条目

iex> Enum.dedup_by(cart, & &1.fruit =~ "a")
[%{fruit: "apple", count: 3}]
iex> Enum.dedup_by(cart, & &1.count < 5)
[
  %{fruit: "apple", count: 3},
  %{fruit: "orange", count: 6}
]

uniq(enum)

uniq 应用于整个集合

iex> Enum.uniq([1, 2, 2, 3, 3, 3, 1, 2, 3])
[1, 2, 3]

推导式也支持 uniq: true 选项。

uniq_by(enum, fun)

获取水果最后一个字母唯一的条目

iex> Enum.uniq_by(cart, &String.last(&1.fruit))
[
  %{fruit: "apple", count: 3},
  %{fruit: "banana", count: 1}
]

索引

at(enum, index, default \\ nil)

iex> Enum.at(cart, 0)
%{fruit: "apple", count: 3}
iex> Enum.at(cart, 10)
nil
iex> Enum.at(cart, 10, :none)
:none

不建议在循环中按索引访问列表。

fetch(enum, index)

iex> Enum.fetch(cart, 0)
{:ok, %{fruit: "apple", count: 3}}
iex> Enum.fetch(cart, 10)
:error

fetch!(enum, index)

iex> Enum.fetch!(cart, 0)
%{fruit: "apple", count: 3}
iex> Enum.fetch!(cart, 10)
** (Enum.OutOfBoundsError) out of bounds error

with_index(enum)

iex> Enum.with_index(cart)
[
  {%{fruit: "apple", count: 3}, 0},
  {%{fruit: "banana", count: 1}, 1},
  {%{fruit: "orange", count: 6}, 2}
]

with_index(enum, fun)

iex> Enum.with_index(cart, fn item, index ->
...>   {item.fruit, index}
...> end)
[
  {"apple", 0},
  {"banana", 1},
  {"orange", 2}
]

查找

find(enum, default \\ nil, fun)

iex> Enum.find(cart, &(&1.fruit =~ "o"))
%{fruit: "orange", count: 6}
iex> Enum.find(cart, &(&1.fruit =~ "y"))
nil
iex> Enum.find(cart, :none, &(&1.fruit =~ "y"))
:none

find_index(enum, fun)

iex> Enum.find_index(cart, &(&1.fruit =~ "o"))
2
iex> Enum.find_index(cart, &(&1.fruit =~ "y"))
nil

find_value(enum, default \\ nil, fun)

iex> Enum.find_value(cart, fn item ->
...>   if item.count == 1, do: item.fruit, else: nil
...> end)
"banana"
iex> Enum.find_value(cart, :none, fn item ->
...>   if item.count == 100, do: item.fruit, else: nil
...> end)
:none

分组

group_by(enum, key_fun)

根据水果的最后一个字母进行分组

iex> Enum.group_by(cart, &String.last(&1.fruit))
%{
  "a" => [%{fruit: "banana", count: 1}],
  "e" => [
    %{fruit: "apple", count: 3},
    %{fruit: "orange", count: 6}
  ]
}

group_by(enum, key_fun, value_fun)

使用自定义值根据水果的最后一个字母进行分组

iex> Enum.group_by(cart, &String.last(&1.fruit), & &1.fruit)
%{
  "a" => ["banana"],
  "e" => ["apple", "orange"]
}

连接 & 插入

join(enum, joiner \\ "")

iex> Enum.join(["apple", "banana", "orange"], ", ")
"apple, banana, orange"

map_join(enum, joiner \\ "", mapper)

iex> Enum.map_join(cart, ", ", & &1.fruit)
"apple, banana, orange"

intersperse(enum, separator \\ "")

iex> Enum.intersperse(["apple", "banana", "orange"], ", ")
["apple", ", ", "banana", ", ", "orange"]

map_intersperse(enum, separator \\ "", mapper)

iex> Enum.map_intersperse(cart, ", ", & &1.fruit)
["apple", ", ", "banana", ", ", "orange"]

切片

slice(enum, index_range)

iex> Enum.slice(cart, 0..1)
[
  %{fruit: "apple", count: 3},
  %{fruit: "banana", count: 1}
]

负范围从尾部计数

iex> Enum.slice(cart, -2..-1)
[
  %{fruit: "banana", count: 1},
  %{fruit: "orange", count: 6}
]

slice(enum, start_index, amount)

iex> Enum.slice(cart, 1, 2)
[
  %{fruit: "banana", count: 1},
  %{fruit: "orange", count: 6}
]

slide(enum, range_or_single_index, insertion_index)

fruits = ["apple", "banana", "grape", "orange", "pear"]
iex> Enum.slide(fruits, 2, 0)
["grape", "apple", "banana", "orange", "pear"]
iex> Enum.slide(fruits, 2, 4)
["apple", "banana", "orange", "pear", "grape", ]
iex> Enum.slide(fruits, 1..3, 0)
["banana", "grape", "orange", "apple", "pear"]
iex> Enum.slide(fruits, 1..3, 4)
["banana", "pear", "grape", "orange", "apple"]

反转

reverse(enum)

iex> Enum.reverse(cart)
[
  %{fruit: "orange", count: 6},
  %{fruit: "banana", count: 1},
  %{fruit: "apple", count: 3}
]

reverse(enum, tail)

iex> Enum.reverse(cart, [:this_will_be, :the_tail])
[
  %{fruit: "orange", count: 6},
  %{fruit: "banana", count: 1},
  %{fruit: "apple", count: 3},
  :this_will_be,
  :the_tail
]

reverse_slice(enum, start_index, count)

iex> Enum.reverse_slice(cart, 1, 2)
[
  %{fruit: "apple", count: 3},
  %{fruit: "orange", count: 6},
  %{fruit: "banana", count: 1}
]

分割

split(enum, amount)

iex> Enum.split(cart, 1)
{[%{fruit: "apple", count: 3}],
 [
   %{fruit: "banana", count: 1},
   %{fruit: "orange", count: 6}
 ]}

负索引从尾部计数

iex> Enum.split(cart, -1)
{[
  %{fruit: "apple", count: 3},
  %{fruit: "banana", count: 1}
 ],
 [%{fruit: "orange", count: 6}]}

split_while(enum, fun)

当它为假时停止分割

iex> Enum.split_while(cart, &(&1.fruit =~ "e"))
{[%{fruit: "apple", count: 3}],
 [
   %{fruit: "banana", count: 1},
   %{fruit: "orange", count: 6}
 ]}

split_with(enum, fun)

分割整个集合

iex> Enum.split_with(cart, &(&1.fruit =~ "e"))
{[
  %{fruit: "apple", count: 3},
  %{fruit: "orange", count: 6}
 ],
 [%{fruit: "banana", count: 1}]}

分割 (drop 和 take)

drop(enum, amount)

iex> Enum.drop(cart, 1)
[
  %{fruit: "banana", count: 1},
  %{fruit: "orange", count: 6}
]

负索引从尾部计数

iex> Enum.drop(cart, -1)
[
  %{fruit: "apple", count: 3},
  %{fruit: "banana", count: 1}
]

drop_every(enum, nth)

iex> Enum.drop_every(cart, 2)
[%{fruit: "banana", count: 1}]

drop_while(enum, fun)

iex> Enum.drop_while(cart, &(&1.fruit =~ "e"))
[
  %{fruit: "banana", count: 1},
  %{fruit: "orange", count: 6}
]

take(enum, amount)

iex> Enum.take(cart, 1)
[%{fruit: "apple", count: 3}]

负索引从尾部计数

iex> Enum.take(cart, -1)
[%{fruit: "orange", count: 6}]

take_every(enum, nth)

iex> Enum.take_every(cart, 2)
[
  %{fruit: "apple", count: 3},
  %{fruit: "orange", count: 6}
]

take_while(enum, fun)

iex> Enum.take_while(cart, &(&1.fruit =~ "e"))
[%{fruit: "apple", count: 3}]

随机

random(enum)

结果每次调用都会有所不同

iex> Enum.random(cart)
%{fruit: "orange", count: 6}

take_random(enum, count)

结果每次调用都会有所不同

iex> Enum.take_random(cart, 2)
[
  %{fruit: "orange", count: 6},
  %{fruit: "apple", count: 3}
]

shuffle(enum)

结果每次调用都会有所不同

iex> Enum.shuffle(cart)
[
  %{fruit: "orange", count: 6},
  %{fruit: "apple", count: 3},
  %{fruit: "banana", count: 1}
]

分块

chunk_by(enum, fun)

iex> Enum.chunk_by(cart, &String.length(&1.fruit))
[
  [%{fruit: "apple", count: 3}],
  [
    %{fruit: "banana", count: 1},
    %{fruit: "orange", count: 6}
  ]
]

chunk_every(enum, count)

iex> Enum.chunk_every(cart, 2)
[
  [
    %{fruit: "apple", count: 3},
    %{fruit: "banana", count: 1}
  ],
  [%{fruit: "orange", count: 6}]
]

chunk_every(enum, count, step, leftover \\ [])

iex> Enum.chunk_every(cart, 2, 2, [:elements, :to_complete])
[
  [
    %{fruit: "apple", count: 3},
    %{fruit: "banana", count: 1}
  ],
  [
    %{fruit: "orange", count: 6},
    :elements
  ]
]
iex> Enum.chunk_every(cart, 2, 1, :discard)
[
  [
    %{fruit: "apple", count: 3},
    %{fruit: "banana", count: 1}
  ],
  [
    %{fruit: "banana", count: 1},
    %{fruit: "orange", count: 6}
  ]
]

参见 Enum.chunk_while/4 用于自定义分块。

压缩

zip(enum1, enum2)

iex> fruits = ["apple", "banana", "orange"]
iex> counts = [3, 1, 6]
iex> Enum.zip(fruits, counts)
[{"apple", 3}, {"banana", 1}, {"orange", 6}]

参见 Enum.zip/1 用于一次压缩多个集合。

zip_with(enum1, enum2, fun)

iex> fruits = ["apple", "banana", "orange"]
iex> counts = [3, 1, 6]
iex> Enum.zip_with(fruits, counts, fn fruit, count ->
...>   %{fruit: fruit, count: count}
...> end)
[
  %{fruit: "apple", count: 3},
  %{fruit: "banana", count: 1},
  %{fruit: "orange", count: 6}
]

参见 Enum.zip_with/2 用于一次压缩多个集合。

zip_reduce(left, right, acc, fun)

iex> fruits = ["apple", "banana", "orange"]
iex> counts = [3, 1, 6]
iex> Enum.zip_reduce(fruits, counts, 0, fn fruit, count, acc ->
...>   price = if fruit =~ "e", do: count * 2, else: count
...>   acc + price
...> end)
19

参见 Enum.zip_reduce/3 用于一次压缩多个集合。

unzip(list)

iex> cart |> Enum.map(&{&1.fruit, &1.count}) |> Enum.unzip()
{["apple", "banana", "orange"], [3, 1, 6]}