檢視原始碼 Enum (Elixir v1.16.2)
處理集合(稱為可列舉)的函式。
在 Elixir 中,可列舉是實作 Enumerable
協定的任何資料類型。 List
([1, 2, 3]
)、Map
(%{foo: 1, bar: 2}
) 和 Range
(1..3
) 是用作可列舉的常見資料類型
iex> Enum.map([1, 2, 3], fn x -> x * 2 end)
[2, 4, 6]
iex> Enum.sum([1, 2, 3])
6
iex> Enum.map(1..3, fn x -> x * 2 end)
[2, 4, 6]
iex> Enum.sum(1..3)
6
iex> map = %{"a" => 1, "b" => 2}
iex> Enum.map(map, fn {k, v} -> {k, v * 2} end)
[{"a", 2}, {"b", 4}]
語言中還有許多其他可列舉,例如 MapSet
和 File.stream!/3
傳回的資料類型,它允許將檔案視為可列舉來遍歷。
若要大致瞭解 Enum
模組中的所有函式,請參閱 Enum
參考手冊。
此模組中的函式以線性時間運作。這表示執行作業所需的時間會隨著可列舉長度以相同的速率成長。這在 Enum.map/2
等作業中是預期的。畢竟,如果我們要遍歷清單中的每個元素,清單越長,我們需要遍歷的元素就越多,而且所需時間也會越長。
這種線性行為也應出現在類似操作中,例如 count/1
、member?/2
、at/2
等。雖然 Elixir 允許資料類型為此類操作提供效能變異,但您不應期望它總是可用,因為 Enum
模組旨在與各種資料類型搭配使用,而且並非所有資料類型都能提供最佳化行為。
最後,請注意 Enum
模組中的函式是急切的:它們會在呼叫後立即遍歷可列舉物件。在使用無限可列舉物件時,這特別危險。在這種情況下,您應使用 Stream
模組,它允許您以延遲方式表達運算,而無需遍歷集合,並使用可能無限的集合。請參閱 Stream
模組以取得範例和文件。
摘要
函式
如果 enumerable
中的所有元素都為真,則傳回 true
。
如果 enumerable
中的所有元素的 fun.(element)
為真,則傳回 true
。
如果 enumerable
中至少有一個元素為真,則傳回 true
。
如果 enumerable
中至少有一個元素的 fun.(element)
為真,則傳回 true
。
尋找給定 index
(從 0 開始) 的元素。
在 fun
傳回新值的每個元素上分割可列舉物件。
簡寫為 chunk_every(enumerable, count, count)
。
傳回包含 count
個元素的清單清單,其中每個新區塊在 enumerable
中的 step
個元素後開始。
以細緻的控制區塊大小來區塊化 可列舉
,並在每個區塊發出時控制。
給定一個可列舉的可列舉,將 可列舉
串接成一個單一清單。
將 右邊
的可列舉與 左邊
的可列舉串接。
傳回 可列舉
的大小。
傳回 可列舉
中 fun
傳回真值元素的數量。
計算可列舉的數量,在 極限
處停止。
計算可列舉中 fun
傳回真值元素的數量,在 極限
處停止。
列舉 可列舉
,傳回一個清單,其中所有連續重複的元素都壓縮成一個單一元素。
列舉 可列舉
,傳回一個清單,其中所有連續重複的元素都壓縮成一個單一元素。
從 可列舉
中移除 數量
的元素。
傳回一個清單,其中 可列舉
中的每個 第 n 個
元素都被移除,從第一個元素開始。
移除 可列舉
開頭的元素,直到 fun
傳回真值。
對 可列舉
中的每個元素呼叫指定的 fun
。
判斷 可列舉
是否為空。
尋找給定 index
(從 0 開始) 的元素。
尋找給定 index
(從 0 開始) 的元素。
過濾 可列舉
,亦即只傳回 fun
傳回真值元素。
傳回第一個 fun
傳回真值的元素。如果找不到此類元素,則傳回 預設
。
類似於 find/3
,但傳回元素的索引(從 0 開始),而不是元素本身。
類似於 find/3
,但傳回函式呼叫的值,而不是元素本身。
將給定的 fun
對 enumerable
進行對應,並將結果扁平化。
對 enumerable
進行對應和簡化,將給定的結果扁平化(僅一層深度)。
傳回一個映射,其中鍵是 enumerable
的唯一元素,而值是每個元素的計數。
傳回一個映射,其中鍵是 key_fun
給出的唯一元素,而值是每個元素的計數。
根據 key_fun
將 enumerable
分割成群組。
在列舉的每個元素之間插入 separator
。
將給定的 enumerable
插入 collectable
中。
根據轉換函數將給定的 enumerable
插入 collectable
中。
使用 joiner
作為分隔符,將給定的 enumerable
加入成一個字串。
傳回一個清單,其中每個元素都是對 enumerable
的每個對應元素呼叫 fun
的結果。
傳回一個清單,其中結果是對 enumerable
的每個 nth
元素(從第一個元素開始)呼叫 fun
的結果。
一次對應和插入給定的列舉。
一次對應和加入給定的 enumerable
。
呼叫給定的函數對 enumerable
中的每個元素,以將其簡化為單一元素,同時保留累加器。
根據 Erlang 的術語排序傳回 enumerable
中的最大元素。
傳回 enumerable
中由給定的 fun
計算出的最大元素。
檢查 元素
是否存在於 可列舉
中。
根據 Erlang 項順序,傳回 可列舉
中的最小元素。
根據指定的 fun
計算,傳回 可列舉
中的最小元素。
根據 Erlang 項順序,傳回一個包含可列舉中最小和最大元素的元組。
根據指定的函數計算,傳回一個包含可列舉中最小和最大元素的元組。
傳回所有元素的乘積。
傳回 可列舉
中的隨機元素。
使用累加器,針對 可列舉
中的每個元素呼叫 fun
。
使用累加器,針對 可列舉
中的每個元素呼叫 fun
。
縮減 可列舉
,直到 fun
傳回 {:halt, 項}
。
傳回 可列舉
中元素的清單,排除函數 fun
傳回真值的元素。
傳回 可列舉
中元素的清單,順序相反。
反轉 可列舉
中的元素,附加 尾
,並以清單的形式傳回。
反轉 可列舉
中從初始 起始索引
到 計數
個元素的範圍。
將給定的函式套用至 enumerable
中的每個元素,將結果儲存在清單中,並將其作為下一次運算的累加器傳遞。使用 enumerable
中的第一個元素作為起始值。
將給定的函式套用至 enumerable
中的每個元素,將結果儲存在清單中,並將其作為下一次運算的累加器傳遞。使用給定的 acc
作為起始值。
傳回一個清單,其中包含 enumerable
的元素,且順序已洗牌。
根據 index_range
傳回給定 enumerable
的子集清單。
傳回給定 enumerable
的子集清單,從 start_index
(以 0 為基準) 開始,包含 amount
個元素(如果有的話)。
將 range_or_single_index
給定的單一或多個元素從 enumerable
滑動到 insertion_index
。
根據 Erlang 的術語排序對 enumerable
進行排序。
根據給定的函式對 enumerable
進行排序。
根據提供的 sorter
函式對 enumerable
的對應結果進行排序。
將 enumerable
分割成兩個 enumerable,在第一個中保留 count
個元素。
在 fun
首次對元素傳回假值 (false
或 nil
) 的位置,將 enumerable 分割成兩個。
根據給定的函式 fun
將 enumerable
分割成兩個清單。
傳回所有元素的總和。
從列舉
的開始或結束處取出數量
的元素。
從列舉
中的第一個元素開始,傳回第n個
元素的清單。
從列舉
中取出計數
個隨機元素。
從列舉
的開始處取出元素,同時函數
傳回真值。
將列舉
轉換為清單。
列舉列舉
,移除所有重複的元素。
列舉列舉
,移除函數函數
傳回重複元素的元素。
傳回列舉
,每個元素都封裝在一個元組中,並附帶其索引。
將有限集合中對應的列舉元素壓縮成元組清單。
將兩個列舉中對應的元素壓縮成元組清單。
縮減所有給定的列舉,只要任何列舉為空就停止。
縮減兩個列舉,只要任何列舉為空就停止。
將有限集合中對應的列舉元素壓縮成清單,並在過程中使用zip_函數
函數轉換它們。
將兩個列舉中對應的元素壓縮成清單,並在過程中使用zip_函數
函數轉換它們。
類型
函數
如果 enumerable
中的所有元素都為真,則傳回 true
。
當一個元素具有假值(false
或 nil
)時,迭代會立即停止,並傳回 false
。在所有其他情況下,會傳回 true
。
範例
iex> Enum.all?([1, 2, 3])
true
iex> Enum.all?([1, nil, 3])
false
iex> Enum.all?([])
true
@spec all?(t(), (element() -> as_boolean(term()))) :: boolean()
如果 enumerable
中的所有元素的 fun.(element)
為真,則傳回 true
。
迭代 enumerable
並在每個元素上呼叫 fun
。如果 fun
曾經傳回假值(false
或 nil
),迭代會立即停止,並傳回 false
。否則,會傳回 true
。
範例
iex> Enum.all?([2, 4, 6], fn x -> rem(x, 2) == 0 end)
true
iex> Enum.all?([2, 3, 4], fn x -> rem(x, 2) == 0 end)
false
iex> Enum.all?([], fn _ -> nil end)
true
如同最後一個範例所示,Enum.all?/2
會傳回 true
,如果 enumerable
為空,不論 fun
為何。在一個空的列舉中,沒有任何元素會讓 fun
傳回假值,所以結果必定是 true
。這是一個定義良好的邏輯論證,適用於空集合。
如果 enumerable
中至少有一個元素為真,則傳回 true
。
當一個元素具有真值(既不是 false
也不是 nil
)時,迭代會立即停止,並傳回 true
。在所有其他情況下,會傳回 false
。
範例
iex> Enum.any?([false, false, false])
false
iex> Enum.any?([false, true, false])
true
iex> Enum.any?([])
false
@spec any?(t(), (element() -> as_boolean(term()))) :: boolean()
如果 enumerable
中至少有一個元素的 fun.(element)
為真,則傳回 true
。
迭代 enumerable
並在每個元素上呼叫 fun
。當呼叫 fun
傳回真值(既不是 false
也不是 nil
)時,迭代會立即停止,並傳回 true
。在所有其他情況下,會傳回 false
。
範例
iex> Enum.any?([2, 4, 6], fn x -> rem(x, 2) == 1 end)
false
iex> Enum.any?([2, 3, 4], fn x -> rem(x, 2) == 1 end)
true
iex> Enum.any?([], fn x -> x > 0 end)
false
尋找給定 index
(從 0 開始) 的元素。
如果 index
超出範圍,傳回 default
。
可以傳入負的 index
,這表示 enumerable
會列舉一次,而 index
會從結尾開始計算(例如,-1
會找到最後一個元素)。
範例
iex> Enum.at([2, 4, 6], 0)
2
iex> Enum.at([2, 4, 6], 2)
6
iex> Enum.at([2, 4, 6], 4)
nil
iex> Enum.at([2, 4, 6], 4, :none)
:none
在 fun
傳回新值的每個元素上分割可列舉物件。
傳回一個列表的列表。
範例
iex> Enum.chunk_by([1, 2, 2, 3, 4, 4, 6, 7, 7], &(rem(&1, 2) == 1))
[[1], [2, 2], [3], [4, 4, 6], [7, 7]]
@spec chunk_every(t(), pos_integer()) :: [list()]
簡寫為 chunk_every(enumerable, count, count)
。
@spec chunk_every(t(), pos_integer(), pos_integer(), t() | :discard) :: [list()]
傳回包含 count
個元素的清單清單,其中每個新區塊在 enumerable
中的 step
個元素後開始。
step
為選用參數,若未傳遞,預設為 count
,亦即區塊不會重疊。當集合結束或我們發出不完整的區塊時,區塊化將停止。
如果最後一個區塊沒有 count
個元素來填滿區塊,將從 leftover
取用元素來填入區塊。如果 leftover
沒有足夠的元素來填滿區塊,則傳回一個小於 count
個元素的部分區塊。
如果在 leftover
中給定 :discard
,則最後一個區塊將被捨棄,除非它剛好有 count
個元素。
範例
iex> Enum.chunk_every([1, 2, 3, 4, 5, 6], 2)
[[1, 2], [3, 4], [5, 6]]
iex> Enum.chunk_every([1, 2, 3, 4, 5, 6], 3, 2, :discard)
[[1, 2, 3], [3, 4, 5]]
iex> Enum.chunk_every([1, 2, 3, 4, 5, 6], 3, 2, [7])
[[1, 2, 3], [3, 4, 5], [5, 6, 7]]
iex> Enum.chunk_every([1, 2, 3, 4], 3, 3, [])
[[1, 2, 3], [4]]
iex> Enum.chunk_every([1, 2, 3, 4], 10)
[[1, 2, 3, 4]]
iex> Enum.chunk_every([1, 2, 3, 4, 5], 2, 3, [])
[[1, 2], [4, 5]]
iex> Enum.chunk_every([1, 2, 3, 4], 3, 3, Stream.cycle([0]))
[[1, 2, 3], [4, 0, 0]]
@spec chunk_while( t(), acc(), (element(), acc() -> {:cont, chunk, acc()} | {:cont, acc()} | {:halt, acc()}), (acc() -> {:cont, chunk, acc()} | {:cont, acc()}) ) :: Enumerable.t() when chunk: any()
以細緻的控制區塊大小來區塊化 可列舉
,並在每個區塊發出時控制。
chunk_fun
接收目前的元素和累加器,且必須傳回
{:cont, chunk, acc}
來發出一個區塊並繼續使用累加器{:cont, acc}
來不發出任何區塊並繼續使用累加器{:halt, acc}
來停止在enumerable
上的區塊化。
after_fun
在反覆運算完成時(或 halt
)以最後的累加器呼叫,以處理任何作為累加器一部份傳回的尾隨元素,但未由 chunk_fun
作為區塊發出。它必須傳回
{:cont, chunk, acc}
來發出一個區塊。區塊將附加到已發出的區塊列表中。{:cont, acc}
來不發出一個區塊
after_fun
中的 acc
是必需的,以便反映 chunk_fun
的元組格式,但由於遍歷已完成,因此它將被捨棄。
傳回一個已發出區塊的列表。
範例
iex> chunk_fun = fn element, acc ->
...> if rem(element, 2) == 0 do
...> {:cont, Enum.reverse([element | acc]), []}
...> else
...> {:cont, [element | acc]}
...> end
...> end
iex> after_fun = fn
...> [] -> {:cont, []}
...> acc -> {:cont, Enum.reverse(acc), []}
...> end
iex> Enum.chunk_while(1..10, [], chunk_fun, after_fun)
[[1, 2], [3, 4], [5, 6], [7, 8], [9, 10]]
iex> Enum.chunk_while([1, 2, 3, 5, 7], [], chunk_fun, after_fun)
[[1, 2], [3, 5, 7]]
給定一個可列舉的可列舉,將 可列舉
串接成一個單一清單。
範例
iex> Enum.concat([1..3, 4..6, 7..9])
[1, 2, 3, 4, 5, 6, 7, 8, 9]
iex> Enum.concat([[1, [2], 3], [4], [5, 6]])
[1, [2], 3, 4, 5, 6]
將 右邊
的可列舉與 左邊
的可列舉串接。
此函數產生與清單的 ++/2
算子相同的結果。
範例
iex> Enum.concat(1..3, 4..6)
[1, 2, 3, 4, 5, 6]
iex> Enum.concat([1, 2, 3], [4, 5, 6])
[1, 2, 3, 4, 5, 6]
@spec count(t()) :: non_neg_integer()
傳回 可列舉
的大小。
範例
iex> Enum.count([1, 2, 3])
3
@spec count(t(), (element() -> as_boolean(term()))) :: non_neg_integer()
傳回 可列舉
中 fun
傳回真值元素的數量。
範例
iex> Enum.count([1, 2, 3, 4, 5], fn x -> rem(x, 2) == 0 end)
2
@spec count_until(t(), pos_integer()) :: non_neg_integer()
計算可列舉的數量,在 極限
處停止。
這對於檢查可列舉項目的計數的特定屬性很有用,而無需實際計數整個可列舉項目。例如,如果你想檢查計數是否正好等於、至少等於或大於某個值。
如果可列舉項目實作 Enumerable.count/1
,則不會遍歷可列舉項目,而且我們會傳回兩個數字中較小的數字。若要強制列舉,請使用 count_until/3
,並將 fn _ -> true end
作為第二個引數。
範例
iex> Enum.count_until(1..20, 5)
5
iex> Enum.count_until(1..20, 50)
20
iex> Enum.count_until(1..10, 10) == 10 # At least 10
true
iex> Enum.count_until(1..11, 10 + 1) > 10 # More than 10
true
iex> Enum.count_until(1..5, 10) < 10 # Less than 10
true
iex> Enum.count_until(1..10, 10 + 1) == 10 # Exactly ten
true
@spec count_until(t(), (element() -> as_boolean(term())), pos_integer()) :: non_neg_integer()
計算可列舉中 fun
傳回真值元素的數量,在 極限
處停止。
請參閱 count/2
和 count_until/2
以取得更多資訊。
範例
iex> Enum.count_until(1..20, fn x -> rem(x, 2) == 0 end, 7)
7
iex> Enum.count_until(1..20, fn x -> rem(x, 2) == 0 end, 11)
10
列舉 可列舉
,傳回一個清單,其中所有連續重複的元素都壓縮成一個單一元素。
元素使用 ===/2
進行比較。
如果你想移除所有重複的元素,不論順序為何,請參閱 uniq/1
。
範例
iex> Enum.dedup([1, 2, 3, 3, 2, 1])
[1, 2, 3, 2, 1]
iex> Enum.dedup([1, 1, 2, 2.0, :three, :three])
[1, 2, 2.0, :three]
列舉 可列舉
,傳回一個清單,其中所有連續重複的元素都壓縮成一個單一元素。
函數 fun
將每個元素對應到一個用於判斷兩個元素是否重複的術語。
範例
iex> Enum.dedup_by([{1, :a}, {2, :b}, {2, :c}, {1, :a}], fn {x, _} -> x end)
[{1, :a}, {2, :b}, {1, :a}]
iex> Enum.dedup_by([5, 1, 2, 3, 2, 1], fn x -> x > 2 end)
[5, 1, 3, 2]
從 可列舉
中移除 數量
的元素。
如果給定負數 amount
,將捨棄最後 amount
個值。將列舉 enumerable
一次以取得適當的索引,並從最後執行其餘的計算。
範例
iex> Enum.drop([1, 2, 3], 2)
[3]
iex> Enum.drop([1, 2, 3], 10)
[]
iex> Enum.drop([1, 2, 3], 0)
[1, 2, 3]
iex> Enum.drop([1, 2, 3], -1)
[1, 2]
@spec drop_every(t(), non_neg_integer()) :: list()
傳回一個清單,其中 可列舉
中的每個 第 n 個
元素都被移除,從第一個元素開始。
第一個元素總是會被捨棄,除非 nth
為 0。
指定每 nth
個元素的第二個參數必須是非負整數。
範例
iex> Enum.drop_every(1..10, 2)
[2, 4, 6, 8, 10]
iex> Enum.drop_every(1..10, 0)
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
iex> Enum.drop_every([1, 2, 3], 1)
[]
@spec drop_while(t(), (element() -> as_boolean(term()))) :: list()
移除 可列舉
開頭的元素,直到 fun
傳回真值。
範例
iex> Enum.drop_while([1, 2, 3, 2, 1], fn x -> x < 3 end)
[3, 2, 1]
對 可列舉
中的每個元素呼叫指定的 fun
。
傳回 :ok
。
範例
Enum.each(["some", "example"], fn x -> IO.puts(x) end)
"some"
"example"
#=> :ok
判斷 可列舉
是否為空。
如果 enumerable
為空,傳回 true
,否則傳回 false
。
範例
iex> Enum.empty?([])
true
iex> Enum.empty?([1, 2, 3])
false
尋找給定 index
(從 0 開始) 的元素。
如果找到,傳回 {:ok, element}
,否則傳回 :error
。
可以傳入負數 index
,表示 enumerable
被列舉一次,而 index
從最後開始計算(例如,-1
會擷取最後一個元素)。
範例
iex> Enum.fetch([2, 4, 6], 0)
{:ok, 2}
iex> Enum.fetch([2, 4, 6], -3)
{:ok, 2}
iex> Enum.fetch([2, 4, 6], 2)
{:ok, 6}
iex> Enum.fetch([2, 4, 6], 4)
:error
尋找給定 index
(從 0 開始) 的元素。
如果給定的 index
超出 enumerable
的範圍,會引發 OutOfBoundsError
。
範例
iex> Enum.fetch!([2, 4, 6], 0)
2
iex> Enum.fetch!([2, 4, 6], 2)
6
iex> Enum.fetch!([2, 4, 6], 4)
** (Enum.OutOfBoundsError) out of bounds error
@spec filter(t(), (element() -> as_boolean(term()))) :: list()
過濾 可列舉
,亦即只傳回 fun
傳回真值元素。
另請參閱 reject/2
,它會捨棄函數傳回真值的所有元素。
範例
iex> Enum.filter([1, 2, 3], fn x -> rem(x, 2) == 0 end)
[2]
請記住,filter
無法同時過濾和轉換元素。如果您想這麼做,請考慮使用 flat_map/2
。例如,如果您想轉換所有表示整數的字串,並在一次傳遞中捨棄無效的字串
strings = ["1234", "abc", "12ab"]
Enum.flat_map(strings, fn string ->
case Integer.parse(string) do
# transform to integer
{int, _rest} -> [int]
# skip the value
:error -> []
end
end)
傳回第一個 fun
傳回真值的元素。如果找不到此類元素,則傳回 預設
。
範例
iex> Enum.find([2, 3, 4], fn x -> rem(x, 2) == 1 end)
3
iex> Enum.find([2, 4, 6], fn x -> rem(x, 2) == 1 end)
nil
iex> Enum.find([2, 4, 6], 0, fn x -> rem(x, 2) == 1 end)
0
@spec find_index(t(), (element() -> any())) :: non_neg_integer() | nil
類似於 find/3
,但傳回元素的索引(從 0 開始),而不是元素本身。
範例
iex> Enum.find_index([2, 4, 6], fn x -> rem(x, 2) == 1 end)
nil
iex> Enum.find_index([2, 3, 4], fn x -> rem(x, 2) == 1 end)
1
@spec find_value(t(), default(), (element() -> found_value)) :: found_value | default() when found_value: term()
類似於 find/3
,但傳回函式呼叫的值,而不是元素本身。
當結果為真值(既不是 nil
也不是 false
)時,回傳值會被視為已找到。
範例
iex> Enum.find_value([2, 3, 4], fn x ->
...> if x > 2, do: x * x
...> end)
9
iex> Enum.find_value([2, 4, 6], fn x -> rem(x, 2) == 1 end)
nil
iex> Enum.find_value([2, 3, 4], fn x -> rem(x, 2) == 1 end)
true
iex> Enum.find_value([1, 2, 3], "no bools!", &is_boolean/1)
"no bools!"
將給定的 fun
對 enumerable
進行對應,並將結果扁平化。
這個函式會回傳一個新的列舉,其建立方式為將呼叫 fun
的結果附加在 enumerable
的每個元素上;從概念上來說,這類似於 map/2
和 concat/1
的組合。
範例
iex> Enum.flat_map([:a, :b, :c], fn x -> [x, x] end)
[:a, :a, :b, :b, :c, :c]
iex> Enum.flat_map([{1, 3}, {4, 6}], fn {x, y} -> x..y end)
[1, 2, 3, 4, 5, 6]
iex> Enum.flat_map([:a, :b, :c], fn x -> [[x]] end)
[[:a], [:b], [:c]]
@spec flat_map_reduce(t(), acc(), fun) :: {[any()], acc()} when fun: (element(), acc() -> {t(), acc()} | {:halt, acc()})
對 enumerable
進行對應和簡化,將給定的結果扁平化(僅一層深度)。
它預期一個累加器和一個接收每個列舉元素的函式,且必須回傳一個包含一個新列舉(通常為清單)的元組,其中包含新的累加器,或一個元組,其中第一個元素為 :halt
,第二個元素為累加器。
範例
iex> enumerable = 1..100
iex> n = 3
iex> Enum.flat_map_reduce(enumerable, 0, fn x, acc ->
...> if acc < n, do: {[x], acc + 1}, else: {:halt, acc}
...> end)
{[1, 2, 3], 3}
iex> Enum.flat_map_reduce(1..5, 0, fn x, acc -> {[[x]], acc + x} end)
{[[1], [2], [3], [4], [5]], 15}
傳回一個映射,其中鍵是 enumerable
的唯一元素,而值是每個元素的計數。
範例
iex> Enum.frequencies(~w{ant buffalo ant ant buffalo dingo})
%{"ant" => 3, "buffalo" => 2, "dingo" => 1}
傳回一個映射,其中鍵是 key_fun
給出的唯一元素,而值是每個元素的計數。
範例
iex> Enum.frequencies_by(~w{aa aA bb cc}, &String.downcase/1)
%{"aa" => 2, "bb" => 1, "cc" => 1}
iex> Enum.frequencies_by(~w{aaa aA bbb cc c}, &String.length/1)
%{3 => 2, 2 => 2, 1 => 1}
根據 key_fun
將 enumerable
分割成群組。
結果是一個映射,其中每個鍵由 key_fun
給出,每個值是由 value_fun
給出的元素清單。每個清單中元素的順序會從 enumerable
保留下來。然而,就像所有映射一樣,產生的映射是無序的。
範例
iex> Enum.group_by(~w{ant buffalo cat dingo}, &String.length/1)
%{3 => ["ant", "cat"], 5 => ["dingo"], 7 => ["buffalo"]}
iex> Enum.group_by(~w{ant buffalo cat dingo}, &String.length/1, &String.first/1)
%{3 => ["a", "c"], 5 => ["d"], 7 => ["b"]}
鍵可以是任何 Elixir 值。例如,你可以使用元組依據多個鍵進行分組
iex> collection = [
...> %{id: 1, lang: "Elixir", seq: 1},
...> %{id: 1, lang: "Java", seq: 1},
...> %{id: 1, lang: "Ruby", seq: 2},
...> %{id: 2, lang: "Python", seq: 1},
...> %{id: 2, lang: "C#", seq: 2},
...> %{id: 2, lang: "Haskell", seq: 2},
...> ]
iex> Enum.group_by(collection, &{&1.id, &1.seq})
%{
{1, 1} => [%{id: 1, lang: "Elixir", seq: 1}, %{id: 1, lang: "Java", seq: 1}],
{1, 2} => [%{id: 1, lang: "Ruby", seq: 2}],
{2, 1} => [%{id: 2, lang: "Python", seq: 1}],
{2, 2} => [%{id: 2, lang: "C#", seq: 2}, %{id: 2, lang: "Haskell", seq: 2}]
}
iex> Enum.group_by(collection, &{&1.id, &1.seq}, &{&1.id, &1.lang})
%{
{1, 1} => [{1, "Elixir"}, {1, "Java"}],
{1, 2} => [{1, "Ruby"}],
{2, 1} => [{2, "Python"}],
{2, 2} => [{2, "C#"}, {2, "Haskell"}]
}
在列舉的每個元素之間插入 separator
。
範例
iex> Enum.intersperse([1, 2, 3], 0)
[1, 0, 2, 0, 3]
iex> Enum.intersperse([1], 0)
[1]
iex> Enum.intersperse([], 0)
[]
@spec into(Enumerable.t(), Collectable.t()) :: Collectable.t()
將給定的 enumerable
插入 collectable
中。
請注意,傳遞一個非空清單作為 collectable
已被棄用。如果你要收集到一個非空的關鍵字清單,請考慮使用 Keyword.merge(collectable, Enum.to_list(enumerable))
。如果你要收集到一個非空的清單,請考慮類似 Enum.to_list(enumerable) ++ collectable
的做法。
範例
iex> Enum.into([1, 2], [])
[1, 2]
iex> Enum.into([a: 1, b: 2], %{})
%{a: 1, b: 2}
iex> Enum.into(%{a: 1}, %{b: 2})
%{a: 1, b: 2}
iex> Enum.into([a: 1, a: 2], %{})
%{a: 2}
iex> Enum.into([a: 2], %{a: 1, b: 3})
%{a: 2, b: 3}
@spec into(Enumerable.t(), Collectable.t(), (term() -> term())) :: Collectable.t()
根據轉換函數將給定的 enumerable
插入 collectable
中。
範例
iex> Enum.into([1, 2, 3], [], fn x -> x * 3 end)
[3, 6, 9]
iex> Enum.into(%{a: 1, b: 2}, %{c: 3}, fn {k, v} -> {k, v * 2} end)
%{a: 2, b: 4, c: 3}
使用 joiner
作為分隔符,將給定的 enumerable
加入成一個字串。
如果 joiner
根本沒有傳遞,它會預設為空字串。
在 enumerable
中的所有元素都必須可以轉換成字串,否則會引發錯誤。
範例
iex> Enum.join([1, 2, 3])
"123"
iex> Enum.join([1, 2, 3], " = ")
"1 = 2 = 3"
iex> Enum.join([["a", "b"], ["c", "d", "e", ["f", "g"]], "h", "i"], " ")
"ab cdefg h i"
傳回一個清單,其中每個元素都是對 enumerable
的每個對應元素呼叫 fun
的結果。
對於地圖,這個函式會預期一個鍵值元組。
範例
iex> Enum.map([1, 2, 3], fn x -> x * 2 end)
[2, 4, 6]
iex> Enum.map([a: 1, b: 2], fn {k, v} -> {k, -v} end)
[a: -1, b: -2]
@spec map_every(t(), non_neg_integer(), (element() -> any())) :: list()
傳回一個清單,其中結果是對 enumerable
的每個 nth
元素(從第一個元素開始)呼叫 fun
的結果。
第一個元素總是傳遞給指定的函式,除非 nth
是 0
。
指定每 nth
個元素的第二個參數必須是非負整數。
如果 nth
是 0
,那麼 enumerable
會直接轉換成一個清單,而不會套用 fun
。
範例
iex> Enum.map_every(1..10, 2, fn x -> x + 1000 end)
[1001, 2, 1003, 4, 1005, 6, 1007, 8, 1009, 10]
iex> Enum.map_every(1..10, 3, fn x -> x + 1000 end)
[1001, 2, 3, 1004, 5, 6, 1007, 8, 9, 1010]
iex> Enum.map_every(1..5, 0, fn x -> x + 1000 end)
[1, 2, 3, 4, 5]
iex> Enum.map_every([1, 2, 3], 1, fn x -> x + 1000 end)
[1001, 1002, 1003]
一次對應和插入給定的列舉。
範例
iex> Enum.map_intersperse([1, 2, 3], :a, &(&1 * 2))
[2, :a, 4, :a, 6]
@spec map_join(t(), String.t(), (element() -> String.Chars.t())) :: String.t()
一次對應和加入給定的 enumerable
。
如果 joiner
根本沒有傳遞,它會預設為空字串。
從呼叫 mapper
回傳的所有元素都必須可以轉換成字串,否則會引發錯誤。
範例
iex> Enum.map_join([1, 2, 3], &(&1 * 2))
"246"
iex> Enum.map_join([1, 2, 3], " = ", &(&1 * 2))
"2 = 4 = 6"
呼叫給定的函數對 enumerable
中的每個元素,以將其簡化為單一元素,同時保留累加器。
傳回一個元組,其中第一個元素是已對應的列舉,第二個元素是最後的累加器。
函數 fun
接收兩個參數:第一個是元素,第二個是累加器。 fun
必須傳回一個包含兩個元素的元組,格式為 {result, accumulator}
。
對於映射,第一個元組元素必須是 {key, value}
元組。
範例
iex> Enum.map_reduce([1, 2, 3], 0, fn x, acc -> {x * 2, x + acc} end)
{[2, 4, 6], 6}
@spec max(t(), (element(), element() -> boolean()) | module(), (-> empty_result)) :: element() | empty_result when empty_result: any()
根據 Erlang 的術語排序傳回 enumerable
中的最大元素。
預設情況下,比較使用 >=
分類函數。如果有多個元素被視為最大值,則傳回第一個找到的元素。如果您希望傳回最後一個被視為最大值的元素,則分類函數不應對相等元素傳回 true。
如果列舉為空,則呼叫提供的 empty_fallback
。預設 empty_fallback
會引發 Enum.EmptyError
。
範例
iex> Enum.max([1, 2, 3])
3
此函數使用 Erlang 的術語排序,表示比較是結構性的,而非語義性的。例如
iex> Enum.max([~D[2017-03-31], ~D[2017-04-01]])
~D[2017-03-31]
在上面的範例中,max/2
傳回 3 月 31 日,而非 4 月 1 日,因為結構性比較會比較年分之前的日期。因此,大多數結構提供「比較」函數,例如 Date.compare/2
,它會接收兩個結構,並傳回 :lt
(小於)、:eq
(等於) 和 :gt
(大於)。如果您傳遞模組作為分類函數,Elixir 會自動使用該模組的 compare/2
函數
iex> Enum.max([~D[2017-03-31], ~D[2017-04-01]], Date)
~D[2017-04-01]
最後,如果您不希望在列舉為空時引發錯誤,您可以傳遞空回退
iex> Enum.max([], &>=/2, fn -> 0 end)
0
max_by(enumerable, fun, sorter \\ &>=/2, empty_fallback \\ fn -> raise Enum.EmptyError end)
檢視來源@spec max_by( t(), (element() -> any()), (element(), element() -> boolean()) | module(), (-> empty_result) ) :: element() | empty_result when empty_result: any()
傳回 enumerable
中由給定的 fun
計算出的最大元素。
預設情況下,比較使用 >=
分類函數。如果有多個元素被視為最大值,則傳回第一個找到的元素。如果您希望傳回最後一個被視為最大值的元素,則分類函數不應對相等元素傳回 true。
呼叫提供的 empty_fallback
函數,如果 enumerable
為空,則傳回其值。預設 empty_fallback
會引發 Enum.EmptyError
。
範例
iex> Enum.max_by(["a", "aa", "aaa"], fn x -> String.length(x) end)
"aaa"
iex> Enum.max_by(["a", "aa", "aaa", "b", "bbb"], &String.length/1)
"aaa"
此函數使用 Erlang 的術語排序,表示比較是結構性的,而非語義性的。因此,如果您要比較結構,大多數結構提供「比較」函數,例如 Date.compare/2
,它會接收兩個結構,並傳回 :lt
(小於)、:eq
(等於) 和 :gt
(大於)。如果您傳遞模組作為分類函數,Elixir 會自動使用該模組的 compare/2
函數
iex> users = [
...> %{name: "Ellis", birthday: ~D[1943-05-11]},
...> %{name: "Lovelace", birthday: ~D[1815-12-10]},
...> %{name: "Turing", birthday: ~D[1912-06-23]}
...> ]
iex> Enum.max_by(users, &(&1.birthday), Date)
%{name: "Ellis", birthday: ~D[1943-05-11]}
最後,如果您不希望在列舉為空時引發錯誤,您可以傳遞空回退
iex> Enum.max_by([], &String.length/1, fn -> nil end)
nil
檢查 元素
是否存在於 可列舉
中。
成員資格會使用配對 (===/2
) 算子進行測試。
範例
iex> Enum.member?(1..10, 5)
true
iex> Enum.member?(1..10, 5.0)
false
iex> Enum.member?([1.0, 2.0, 3.0], 2)
false
iex> Enum.member?([1.0, 2.0, 3.0], 2.000)
true
iex> Enum.member?([:a, :b, :c], :d)
false
@spec min(t(), (element(), element() -> boolean()) | module(), (-> empty_result)) :: element() | empty_result when empty_result: any()
根據 Erlang 項順序,傳回 可列舉
中的最小元素。
預設情況下,比較會使用 <=
分類函數。如果有多個元素被視為最小,則會傳回找到的第一個元素。如果您希望傳回被視為最小的最後一個元素,則分類函數不應對相等元素傳回 true。
如果列舉為空,則呼叫提供的 empty_fallback
。預設 empty_fallback
會引發 Enum.EmptyError
。
範例
iex> Enum.min([1, 2, 3])
1
此函數使用 Erlang 的術語排序,表示比較是結構性的,而非語義性的。例如
iex> Enum.min([~D[2017-03-31], ~D[2017-04-01]])
~D[2017-04-01]
在上述範例中,min/2
傳回 4 月 1 日,而不是 3 月 31 日,因為結構比較會比較年份的前一天。因此,大多數結構會提供「比較」函數,例如 Date.compare/2
,它會接收兩個結構並傳回 :lt
(小於)、:eq
(等於) 和 :gt
(大於)。如果您傳遞模組作為分類函數,Elixir 會自動使用該模組的 compare/2
函數
iex> Enum.min([~D[2017-03-31], ~D[2017-04-01]], Date)
~D[2017-03-31]
最後,如果您不希望在列舉為空時引發錯誤,您可以傳遞空回退
iex> Enum.min([], fn -> 0 end)
0
@spec min_by( t(), (element() -> any()), (element(), element() -> boolean()) | module(), (-> empty_result) ) :: element() | empty_result when empty_result: any()
根據指定的 fun
計算,傳回 可列舉
中的最小元素。
預設情況下,比較會使用 <=
分類函數。如果有多個元素被視為最小,則會傳回找到的第一個元素。如果您希望傳回被視為最小的最後一個元素,則分類函數不應對相等元素傳回 true。
呼叫提供的 empty_fallback
函數,如果 enumerable
為空,則傳回其值。預設 empty_fallback
會引發 Enum.EmptyError
。
範例
iex> Enum.min_by(["a", "aa", "aaa"], fn x -> String.length(x) end)
"a"
iex> Enum.min_by(["a", "aa", "aaa", "b", "bbb"], &String.length/1)
"a"
此函數使用 Erlang 的術語排序,表示比較是結構性的,而非語義性的。因此,如果您要比較結構,大多數結構提供「比較」函數,例如 Date.compare/2
,它會接收兩個結構,並傳回 :lt
(小於)、:eq
(等於) 和 :gt
(大於)。如果您傳遞模組作為分類函數,Elixir 會自動使用該模組的 compare/2
函數
iex> users = [
...> %{name: "Ellis", birthday: ~D[1943-05-11]},
...> %{name: "Lovelace", birthday: ~D[1815-12-10]},
...> %{name: "Turing", birthday: ~D[1912-06-23]}
...> ]
iex> Enum.min_by(users, &(&1.birthday), Date)
%{name: "Lovelace", birthday: ~D[1815-12-10]}
最後,如果您不希望在列舉為空時引發錯誤,您可以傳遞空回退
iex> Enum.min_by([], &String.length/1, fn -> nil end)
nil
@spec min_max(t(), (-> empty_result)) :: {element(), element()} | empty_result when empty_result: any()
根據 Erlang 項順序,傳回一個包含可列舉中最小和最大元素的元組。
如果有多個元素被視為最大或最小,則會傳回找到的第一個元素。
呼叫提供的 empty_fallback
函數,如果 enumerable
為空,則傳回其值。預設 empty_fallback
會引發 Enum.EmptyError
。
範例
iex> Enum.min_max([2, 3, 1])
{1, 3}
iex> Enum.min_max([], fn -> {nil, nil} end)
{nil, nil}
@spec min_max_by( t(), (element() -> any()), (element(), element() -> boolean()) | module(), (-> empty_result) ) :: {element(), element()} | empty_result when empty_result: any()
根據指定的函數計算,傳回一個包含可列舉中最小和最大元素的元組。
如果有多個元素被視為最大或最小,則會傳回找到的第一個元素。
範例
iex> Enum.min_max_by(["aaa", "bb", "c"], fn x -> String.length(x) end)
{"c", "aaa"}
iex> Enum.min_max_by(["aaa", "a", "bb", "c", "ccc"], &String.length/1)
{"a", "aaa"}
iex> Enum.min_max_by([], &String.length/1, fn -> {nil, nil} end)
{nil, nil}
此函數使用 Erlang 的術語排序,表示比較是結構性的,而非語義性的。因此,如果您要比較結構,大多數結構提供「比較」函數,例如 Date.compare/2
,它會接收兩個結構,並傳回 :lt
(小於)、:eq
(等於) 和 :gt
(大於)。如果您傳遞模組作為分類函數,Elixir 會自動使用該模組的 compare/2
函數
iex> users = [
...> %{name: "Ellis", birthday: ~D[1943-05-11]},
...> %{name: "Lovelace", birthday: ~D[1815-12-10]},
...> %{name: "Turing", birthday: ~D[1912-06-23]}
...> ]
iex> Enum.min_max_by(users, &(&1.birthday), Date)
{
%{name: "Lovelace", birthday: ~D[1815-12-10]},
%{name: "Ellis", birthday: ~D[1943-05-11]}
}
最後,如果您不希望在列舉為空時引發錯誤,您可以傳遞空回退
iex> Enum.min_max_by([], &String.length/1, fn -> nil end)
nil
傳回所有元素的乘積。
如果 enumerable
包含非數字值,則會引發 ArithmeticError
。
範例
iex> Enum.product([])
1
iex> Enum.product([2, 3, 4])
24
iex> Enum.product([2.0, 3.0, 4.0])
24.0
傳回 可列舉
中的隨機元素。
如果 enumerable
為空,則會引發 Enum.EmptyError
。
此函數使用 Erlang 的 :rand
模組 來計算隨機值。請查看其文件以設定不同的隨機演算法或不同的種子。
實作是基於蓄水池抽樣演算法。它假設回傳的範例可以放入記憶體中;輸入的可列舉
不必,因為它只會遍歷一次。
如果函式中傳入一個範圍,此函式會在範圍限制中挑選一個隨機值,而不用遍歷整個範圍(因此執行時間和記憶體都是常數)。
範例
以下範例使用:exsss
偽亂數演算法,因為它是 Erlang/OTP 22 的預設值
# Although not necessary, let's seed the random algorithm
iex> :rand.seed(:exsss, {100, 101, 102})
iex> Enum.random([1, 2, 3])
2
iex> Enum.random([1, 2, 3])
1
iex> Enum.random(1..1_000)
309
使用累加器,針對 可列舉
中的每個元素呼叫 fun
。
如果 enumerable
為空,則會引發 Enum.EmptyError
。
可列舉
的第一個元素用作累加器的初始值。然後,函式會使用下一個元素和累加器呼叫。函式回傳的結果會用作下一次反覆運算的累加器,遞迴進行。當可列舉
完成時,會回傳最後的累加器。
由於可列舉的第一個元素用作累加器的初始值,fun
只會執行n - 1
次,其中n
是可列舉的長度。此函式不會為長度為一的可列舉呼叫指定函式。
如果你想為累加器使用另一個值,請使用Enum.reduce/3
。
範例
iex> Enum.reduce([1, 2, 3, 4], fn x, acc -> x * acc end)
24
使用累加器,針對 可列舉
中的每個元素呼叫 fun
。
累加器的初始值是acc
。函式會使用累加器呼叫可列舉中的每個元素。函式回傳的結果會用作下一次反覆運算的累加器。函式會回傳最後的累加器。
範例
iex> Enum.reduce([1, 2, 3], 0, fn x, acc -> x + acc end)
6
iex> Enum.reduce(%{a: 2, b: 3, c: 4}, 0, fn {_key, val}, acc -> acc + val end)
9
Reduce 作為建構區塊
Reduce(有時稱為fold
)是函式程式設計中的基本建構區塊。Enum
模組中幾乎所有的函式都可以實作在 reduce 上。這些函式通常依賴於其他運算,例如Enum.reverse/1
,這些運算會由執行時期最佳化。
例如,我們可以透過 reduce/3
來實作 map/2
,如下所示
def my_map(enumerable, fun) do
enumerable
|> Enum.reduce([], fn x, acc -> [fun.(x) | acc] end)
|> Enum.reverse()
end
在上面的範例中,Enum.reduce/3
會將每次呼叫 fun
的結果累積成一個清單,並以反向順序排列,最後再呼叫 Enum.reverse/1
來正確排序。
實作像 map/2
、filter/2
等函式,是了解 Enum.reduce/3
強大的好練習。當 Enum
模組中的函式無法表達某個操作時,開發人員很可能會求助於 reduce/3
。
縮減 可列舉
,直到 fun
傳回 {:halt, 項}
。
預期 fun
的傳回值為
{:cont, acc}
以acc
作為新的累加器繼續縮減,或{:halt, acc}
以停止縮減
如果 fun
傳回 {:halt, acc}
,縮減就會停止,且函式會傳回 acc
。否則,如果可列舉物件已用盡,函式會傳回最後一個 {:cont, acc}
的累加器。
範例
iex> Enum.reduce_while(1..100, 0, fn x, acc ->
...> if x < 5 do
...> {:cont, acc + x}
...> else
...> {:halt, acc}
...> end
...> end)
10
iex> Enum.reduce_while(1..100, 0, fn x, acc ->
...> if x > 0 do
...> {:cont, acc + x}
...> else
...> {:halt, acc}
...> end
...> end)
5050
@spec reject(t(), (element() -> as_boolean(term()))) :: list()
傳回 可列舉
中元素的清單,排除函數 fun
傳回真值的元素。
另請參閱 filter/2
。
範例
iex> Enum.reject([1, 2, 3], fn x -> rem(x, 2) == 0 end)
[1, 3]
傳回 可列舉
中元素的清單,順序相反。
範例
iex> Enum.reverse([1, 2, 3])
[3, 2, 1]
反轉 可列舉
中的元素,附加 尾
,並以清單的形式傳回。
這是針對 enumerable |> Enum.reverse() |> Enum.concat(tail)
的最佳化。
範例
iex> Enum.reverse([1, 2, 3], [4, 5, 6])
[3, 2, 1, 4, 5, 6]
@spec reverse_slice(t(), non_neg_integer(), non_neg_integer()) :: list()
反轉 可列舉
中從初始 起始索引
到 計數
個元素的範圍。
如果 count
大於 enumerable
其餘部分的大小,則此函式會反轉可列舉物件的其餘部分。
範例
iex> Enum.reverse_slice([1, 2, 3, 4, 5, 6], 2, 4)
[1, 2, 6, 5, 4, 3]
將給定的函式套用至 enumerable
中的每個元素,將結果儲存在清單中,並將其作為下一次運算的累加器傳遞。使用 enumerable
中的第一個元素作為起始值。
範例
iex> Enum.scan(1..5, &(&1 + &2))
[1, 3, 6, 10, 15]
將給定的函式套用至 enumerable
中的每個元素,將結果儲存在清單中,並將其作為下一次運算的累加器傳遞。使用給定的 acc
作為起始值。
範例
iex> Enum.scan(1..5, 0, &(&1 + &2))
[1, 3, 6, 10, 15]
傳回一個清單,其中包含 enumerable
的元素,且順序已洗牌。
此函數使用 Erlang 的 :rand
模組 來計算隨機值。請查看其文件以設定不同的隨機演算法或不同的種子。
範例
以下範例使用:exsss
偽亂數演算法,因為它是 Erlang/OTP 22 的預設值
# Although not necessary, let's seed the random algorithm
iex> :rand.seed(:exsss, {1, 2, 3})
iex> Enum.shuffle([1, 2, 3])
[3, 2, 1]
iex> Enum.shuffle([1, 2, 3])
[2, 1, 3]
根據 index_range
傳回給定 enumerable
的子集清單。
index_range
必須為 Range
。給定一個 enumerable
,它會捨棄 index_range.first
(以 0 為基準)之前的元素,然後取用直到元素 index_range.last
(包含)的元素。
索引經過正規化,表示負索引將從結尾開始計算(例如,-1
表示 enumerable
的最後一個元素)。
如果 index_range.last
超出範圍,則會將其指定為最後一個元素的索引。
如果正規化後的 index_range.first
超出給定 enumerable
的範圍,或者這個範圍大於正規化後的 index_range.last
,則會傳回 []
。
如果在 index_range
中使用步驟 n
(除了 1
),則會從 index_range.first
到 index_range.last
取用每 n
個元素(根據上述相同的規則)。
範例
iex> Enum.slice([1, 2, 3, 4, 5], 1..3)
[2, 3, 4]
iex> Enum.slice([1, 2, 3, 4, 5], 3..10)
[4, 5]
# Last three elements (negative indexes)
iex> Enum.slice([1, 2, 3, 4, 5], -3..-1)
[3, 4, 5]
對於 start > stop
的範圍,您需要明確標記它們為遞增
iex> Enum.slice([1, 2, 3, 4, 5], 1..-2//1)
[2, 3, 4]
步驟可以是任何正數。例如,要取得集合中的每 2 個元素
iex> Enum.slice([1, 2, 3, 4, 5], 0..-1//2)
[1, 3, 5]
要取得前十個元素中的每三個元素
iex> integers = Enum.to_list(1..20)
iex> Enum.slice(integers, 0..9//3)
[1, 4, 7, 10]
如果第一個位置在可列舉的結尾之後或在範圍的最後一個位置之後,則會傳回一個空清單
iex> Enum.slice([1, 2, 3, 4, 5], 6..10)
[]
# first is greater than last
iex> Enum.slice([1, 2, 3, 4, 5], 6..5//1)
[]
@spec slice(t(), index(), non_neg_integer()) :: list()
傳回給定 enumerable
的子集清單,從 start_index
(以 0 為基準) 開始,包含 amount
個元素(如果有的話)。
給定一個 enumerable
,它會捨棄元素 start_index
之前的元素;然後,它會取用 amount
個元素,如果元素不足,則傳回盡可能多的元素。
可以傳遞負的 start_index
,表示 enumerable
被列舉一次,且索引從尾端開始計算(例如,-1
從最後一個元素開始切片)。
如果 amount
為 0
或 start_index
超出範圍,則傳回 []
。
範例
iex> Enum.slice(1..100, 5, 10)
[6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
# amount to take is greater than the number of elements
iex> Enum.slice(1..10, 5, 100)
[6, 7, 8, 9, 10]
iex> Enum.slice(1..10, 5, 0)
[]
# using a negative start index
iex> Enum.slice(1..10, -6, 3)
[5, 6, 7]
iex> Enum.slice(1..10, -11, 5)
[1, 2, 3, 4, 5]
# out of bound start index
iex> Enum.slice(1..10, 10, 5)
[]
將 range_or_single_index
給定的單一或多個元素從 enumerable
滑動到 insertion_index
。
要移動的範圍語意與 Enum.slice/2
的語意相同。具體來說,表示
索引已正規化,表示負索引會從尾端開始計算(例如,-1 表示列舉項目的最後一個元素)。對於像清單這類無法提供恆定時間計算的類型,這將導致列舉項目兩次遍歷。
如果正規化索引範圍的
last
超出範圍,則範圍會截斷到最後一個元素。如果正規化索引範圍的
first
超出範圍,則選取的滑動範圍會是空的,因此您會取回輸入清單。遞減的範圍(例如
5..0//1
)也會選取一個空的範圍來移動,因此您會取回輸入清單。任何步驟不是 1 的範圍都會引發錯誤。
範例
# Slide a single element
iex> Enum.slide([:a, :b, :c, :d, :e, :f, :g], 5, 1)
[:a, :f, :b, :c, :d, :e, :g]
# Slide a range of elements backward
iex> Enum.slide([:a, :b, :c, :d, :e, :f, :g], 3..5, 1)
[:a, :d, :e, :f, :b, :c, :g]
# Slide a range of elements forward
iex> Enum.slide([:a, :b, :c, :d, :e, :f, :g], 1..3, 5)
[:a, :e, :f, :b, :c, :d, :g]
# Slide with negative indices (counting from the end)
iex> Enum.slide([:a, :b, :c, :d, :e, :f, :g], 3..-1//1, 2)
[:a, :b, :d, :e, :f, :g, :c]
iex> Enum.slide([:a, :b, :c, :d, :e, :f, :g], -4..-2, 1)
[:a, :d, :e, :f, :b, :c, :g]
# Insert at negative indices (counting from the end)
iex> Enum.slide([:a, :b, :c, :d, :e, :f, :g], 3, -1)
[:a, :b, :c, :e, :f, :g, :d]
根據 Erlang 的術語排序對 enumerable
進行排序。
此函式使用合併排序演算法。請勿使用此函式來排序結構,請參閱 sort/2
以取得更多資訊。
範例
iex> Enum.sort([3, 2, 1])
[1, 2, 3]
@spec sort( t(), (element(), element() -> boolean()) | :asc | :desc | module() | {:asc | :desc, module()} ) :: list()
根據給定的函式對 enumerable
進行排序。
此函式使用合併排序演算法。所提供的函式應比較兩個引數,並在第一個引數先於或與第二個引數相同時傳回 true
。
範例
iex> Enum.sort([1, 2, 3], &(&1 >= &2))
[3, 2, 1]
只要所提供的函式對視為相等的數值傳回 true
,排序演算法就會是穩定的
iex> Enum.sort(["some", "kind", "of", "monster"], &(byte_size(&1) <= byte_size(&2)))
["of", "some", "kind", "monster"]
如果函式未對相等數值傳回 true
,則排序是不穩定的,且相等項目的順序可能會洗牌。例如
iex> Enum.sort(["some", "kind", "of", "monster"], &(byte_size(&1) < byte_size(&2)))
["of", "kind", "some", "monster"]
遞增和遞減 (自 v1.10.0 起)
sort/2
允許開發人員傳遞 :asc
或 :desc
作為排序器,這方便 &<=/2
和 &>=/2
分別使用。
iex> Enum.sort([2, 3, 1], :asc)
[1, 2, 3]
iex> Enum.sort([2, 3, 1], :desc)
[3, 2, 1]
排序結構
排序結構時,請勿使用 </2
、<=/2
、>/2
、>=/2
及其相關函數。這是因為上述內建運算子會執行結構比較,而非語意比較。假設我們要對下列日期清單進行排序
iex> dates = [~D[2019-01-01], ~D[2020-03-02], ~D[2019-06-06]]
iex> Enum.sort(dates)
[~D[2019-01-01], ~D[2020-03-02], ~D[2019-06-06]]
請注意,傳回的結果不正確,因為 sort/1
預設會使用 <=/2
,而它會比較它們的結構。比較結構時,會按照字母順序比較欄位,這表示上述日期會依 day
、month
,再依 year
進行比較,這與我們預期的相反。
因此,大多數結構會提供「比較」函數,例如 Date.compare/2
,它會接收兩個結構並傳回 :lt
(小於)、:eq
(等於) 和 :gt
(大於)。如果您傳遞模組作為排序函數,Elixir 會自動使用該模組的 compare/2
函數
iex> dates = [~D[2019-01-01], ~D[2020-03-02], ~D[2019-06-06]]
iex> Enum.sort(dates, Date)
[~D[2019-01-01], ~D[2019-06-06], ~D[2020-03-02]]
若要按遞減順序擷取所有日期,您可以使用 :asc
或 :desc
將模組包在一個元組中,並將其作為第一個元素
iex> dates = [~D[2019-01-01], ~D[2020-03-02], ~D[2019-06-06]]
iex> Enum.sort(dates, {:asc, Date})
[~D[2019-01-01], ~D[2019-06-06], ~D[2020-03-02]]
iex> dates = [~D[2019-01-01], ~D[2020-03-02], ~D[2019-06-06]]
iex> Enum.sort(dates, {:desc, Date})
[~D[2020-03-02], ~D[2019-06-06], ~D[2019-01-01]]
@spec sort_by( t(), (element() -> mapped_element), (element(), element() -> boolean()) | :asc | :desc | module() | {:asc | :desc, module()} ) :: list() when mapped_element: element()
根據提供的 sorter
函式對 enumerable
的對應結果進行排序。
此函數會使用提供的 mapper
函數對 enumerable
的每個元素進行對應。接著,會使用 sorter
對對應的元素進行排序,其預設值為 :asc
,並會以遞增順序對元素進行排序。
sort_by/3
與 sort/2
的不同之處在於,它只會計算 enumerable
中每個元素的比較值一次,而不是在每次比較中為每個元素計算一次。如果對兩個元素呼叫相同的函數,使用 sort_by/3
會更有效率。
遞增和遞減 (自 v1.10.0 起)
sort_by/3
允許開發人員傳遞 :asc
或 :desc
作為 sorter
,這分別是 &<=/2
和 &>=/2
的簡便寫法
iex> Enum.sort_by([2, 3, 1], &(&1), :asc)
[1, 2, 3]
iex> Enum.sort_by([2, 3, 1], &(&1), :desc)
[3, 2, 1]
範例
使用 sorter
的預設值 :asc
iex> Enum.sort_by(["some", "kind", "of", "monster"], &byte_size/1)
["of", "some", "kind", "monster"]
依據多個屬性排序 - 先依據大小,再依據第一個字母 (這利用了元組按元素比較的事實)
iex> Enum.sort_by(["some", "kind", "of", "monster"], &{byte_size(&1), String.first(&1)})
["of", "kind", "some", "monster"]
類似於 sort/2
,你可以傳遞自訂的排序器
iex> Enum.sort_by(["some", "kind", "of", "monster"], &byte_size/1, :desc)
["monster", "some", "kind", "of"]
與 sort/2
一樣,避免使用預設的排序函式來排序結構,因為它預設執行結構比較,而不是語義比較。在這種情況下,你應傳遞排序函式作為第三個元素或任何實作 compare/2
函式的模組。例如,分別依據使用者的生日以遞增和遞減順序排序
iex> users = [
...> %{name: "Ellis", birthday: ~D[1943-05-11]},
...> %{name: "Lovelace", birthday: ~D[1815-12-10]},
...> %{name: "Turing", birthday: ~D[1912-06-23]}
...> ]
iex> Enum.sort_by(users, &(&1.birthday), Date)
[
%{name: "Lovelace", birthday: ~D[1815-12-10]},
%{name: "Turing", birthday: ~D[1912-06-23]},
%{name: "Ellis", birthday: ~D[1943-05-11]}
]
iex> Enum.sort_by(users, &(&1.birthday), {:desc, Date})
[
%{name: "Ellis", birthday: ~D[1943-05-11]},
%{name: "Turing", birthday: ~D[1912-06-23]},
%{name: "Lovelace", birthday: ~D[1815-12-10]}
]
效能特性
如初始區段所述,sort_by/3
計算可列舉中每個元素的比較值一次,而不是每次比較中每個元素一次。這表示 sort_by/3
必須對資料進行初始傳遞以計算這些值。
但是,如果這些值很容易計算,例如,你已經將想要排序的欄位萃取到元組中,那麼這些額外的傳遞就會變成負擔。在這種情況下,請考慮改用 List.keysort/3
。
我們來看一個範例。想像你有一個產品清單,還有一個 ID 清單。你想要保留給定 ID 中的所有產品,並依據其價格對其名稱進行排序。你可以這樣寫
for(
product <- products,
product.id in ids,
do: product
)
|> Enum.sort_by(& &1.price)
|> Enum.map(& &1.name)
但是,你也可以這樣寫
for(
product <- products,
product.id in ids,
do: {product.name, product.price}
)
|> List.keysort(1)
|> Enum.map(&elem(&1, 0))
對於效能敏感的程式碼,使用 List.keysort/3
會是更好的選擇,因為它避免了額外的遍歷。
將 enumerable
分割成兩個 enumerable,在第一個中保留 count
個元素。
如果 count
是負數,它會從 enumerable
的最後開始往回計數。
請注意,負 count
表示 enumerable
將被列舉兩次:一次計算位置,第二次執行實際分割。
範例
iex> Enum.split([1, 2, 3], 2)
{[1, 2], [3]}
iex> Enum.split([1, 2, 3], 10)
{[1, 2, 3], []}
iex> Enum.split([1, 2, 3], 0)
{[], [1, 2, 3]}
iex> Enum.split([1, 2, 3], -1)
{[1, 2], [3]}
iex> Enum.split([1, 2, 3], -5)
{[], [1, 2, 3]}
在 fun
首次對元素傳回假值 (false
或 nil
) 的位置,將 enumerable 分割成兩個。
傳回一個二元組,其中包含兩個元素清單。觸發分割的元素是第二個清單的一部分。
範例
iex> Enum.split_while([1, 2, 3, 4], fn x -> x < 3 end)
{[1, 2], [3, 4]}
iex> Enum.split_while([1, 2, 3, 4], fn x -> x < 0 end)
{[], [1, 2, 3, 4]}
iex> Enum.split_while([1, 2, 3, 4], fn x -> x > 0 end)
{[1, 2, 3, 4], []}
根據給定的函式 fun
將 enumerable
分割成兩個清單。
透過呼叫 fun
,並將 enumerable
中的每個元素作為其唯一參數,將指定的 enumerable
分割成兩個清單。傳回一個二元組,其中第一個清單包含 enumerable
中所有套用 fun
後傳回真值的元素,而第二個清單則包含所有套用 fun
後傳回假值的元素(false
或 nil
)。
傳回清單中元素的相對順序與其在原始可列舉中的順序相同(如果可列舉是有序的,例如清單)。請參閱下列範例。
範例
iex> Enum.split_with([5, 4, 3, 2, 1, 0], fn x -> rem(x, 2) == 0 end)
{[4, 2, 0], [5, 3, 1]}
iex> Enum.split_with([a: 1, b: -2, c: 1, d: -3], fn {_k, v} -> v < 0 end)
{[b: -2, d: -3], [a: 1, c: 1]}
iex> Enum.split_with([a: 1, b: -2, c: 1, d: -3], fn {_k, v} -> v > 50 end)
{[], [a: 1, b: -2, c: 1, d: -3]}
iex> Enum.split_with([], fn {_k, v} -> v > 50 end)
{[], []}
傳回所有元素的總和。
如果 enumerable
包含非數字值,則會引發 ArithmeticError
。
範例
iex> Enum.sum([1, 2, 3])
6
iex> Enum.sum(1..10)
55
iex> Enum.sum(1..10//2)
25
從列舉
的開始或結束處取出數量
的元素。
如果指定正數 amount
,則會從 enumerable
開頭擷取 amount
個元素。
如果指定負數 amount
,則會從結尾擷取 amount
個元素。會列舉 enumerable
一次以取得正確的索引,並從結尾執行其餘的計算。
如果 amount 為 0
,則會傳回 []
。
範例
iex> Enum.take([1, 2, 3], 2)
[1, 2]
iex> Enum.take([1, 2, 3], 10)
[1, 2, 3]
iex> Enum.take([1, 2, 3], 0)
[]
iex> Enum.take([1, 2, 3], -1)
[3]
@spec take_every(t(), non_neg_integer()) :: list()
從列舉
中的第一個元素開始,傳回第n個
元素的清單。
第一個元素始終會包含在內,除非 nth
為 0。
指定每 nth
個元素的第二個參數必須是非負整數。
範例
iex> Enum.take_every(1..10, 2)
[1, 3, 5, 7, 9]
iex> Enum.take_every(1..10, 0)
[]
iex> Enum.take_every([1, 2, 3], 1)
[1, 2, 3]
@spec take_random(t(), non_neg_integer()) :: list()
從列舉
中取出計數
個隨機元素。
請注意,此函式會遍歷整個 enumerable
以取得隨機子清單。
請參閱 random/1
以取得有關實作和隨機種子的注意事項。
範例
# Although not necessary, let's seed the random algorithm
iex> :rand.seed(:exsss, {1, 2, 3})
iex> Enum.take_random(1..10, 2)
[3, 1]
iex> Enum.take_random(?a..?z, 5)
'mikel'
@spec take_while(t(), (element() -> as_boolean(term()))) :: list()
從列舉
的開始處取出元素,同時函數
傳回真值。
範例
iex> Enum.take_while([1, 2, 3], fn x -> x < 3 end)
[1, 2]
將列舉
轉換為清單。
範例
iex> Enum.to_list(1..3)
[1, 2, 3]
列舉列舉
,移除所有重複的元素。
範例
iex> Enum.uniq([1, 2, 3, 3, 2, 1])
[1, 2, 3]
列舉列舉
,移除函數函數
傳回重複元素的元素。
函數 fun
將每個元素對應到一個項目。如果兩個元素的 fun
回傳值相等,則這兩個元素視為重複。
會保留每個元素第一次出現的項目。
範例
iex> Enum.uniq_by([{1, :x}, {2, :y}, {1, :z}], fn {x, _} -> x end)
[{1, :x}, {2, :y}]
iex> Enum.uniq_by([a: {:tea, 2}, b: {:tea, 2}, c: {:coffee, 1}], fn {_, y} -> y end)
[a: {:tea, 2}, c: {:coffee, 1}]
zip/2
的反義詞。從給定的列舉
中萃取二元組,並將它們分組在一起。
它接收一個 可列舉
,其元素為兩個元素的元組,並回傳一個元組,其中包含兩個清單,每個清單分別由每個元組的第一個和第二個元素組成。
除非 可列舉
是或可以轉換為元組清單,且每個元組中正好包含兩個元素,否則此函數會失敗。
範例
iex> Enum.unzip([{:a, 1}, {:b, 2}, {:c, 3}])
{[:a, :b, :c], [1, 2, 3]}
@spec with_index(t(), integer()) :: [{term(), integer()}]
@spec with_index(t(), (element(), index() -> value)) :: [value] when value: any()
傳回列舉
,每個元素都封裝在一個元組中,並附帶其索引。
可以接收函數或整數偏移量。
如果給定 偏移量
,它將從給定的偏移量而不是從零開始索引。
如果給定 函數
,它將透過對可列舉的每個元素和索引(從零開始)呼叫函數來索引。
範例
iex> Enum.with_index([:a, :b, :c])
[a: 0, b: 1, c: 2]
iex> Enum.with_index([:a, :b, :c], 3)
[a: 3, b: 4, c: 5]
iex> Enum.with_index([:a, :b, :c], fn element, index -> {index, element} end)
[{0, :a}, {1, :b}, {2, :c}]
將有限集合中對應的列舉元素壓縮成元組清單。
只要給定集合中的任何可列舉完成,就會完成壓縮。
範例
iex> Enum.zip([[1, 2, 3], [:a, :b, :c], ["foo", "bar", "baz"]])
[{1, :a, "foo"}, {2, :b, "bar"}, {3, :c, "baz"}]
iex> Enum.zip([[1, 2, 3, 4, 5], [:a, :b, :c]])
[{1, :a}, {2, :b}, {3, :c}]
將兩個列舉中對應的元素壓縮成元組清單。
只要任一可列舉完成,就會完成壓縮。
範例
iex> Enum.zip([1, 2, 3], [:a, :b, :c])
[{1, :a}, {2, :b}, {3, :c}]
iex> Enum.zip([1, 2, 3, 4, 5], [:a, :b, :c])
[{1, :a}, {2, :b}, {3, :c}]
縮減所有給定的列舉,只要任何列舉為空就停止。
還原器將接收 2 個參數:元素清單(每個列舉一個)和累加器。
在實務上,此函數提供的行為可以用下列方式達成:
Enum.reduce(Stream.zip(enums), acc, reducer)
但 zip_reduce/3
是為了方便而存在的。
範例
iex> enums = [[1, 1], [2, 2], [3, 3]]
...> Enum.zip_reduce(enums, [], fn elements, acc ->
...> [List.to_tuple(elements) | acc]
...> end)
[{1, 2, 3}, {1, 2, 3}]
iex> enums = [[1, 2], [a: 3, b: 4], [5, 6]]
...> Enum.zip_reduce(enums, [], fn elements, acc ->
...> [List.to_tuple(elements) | acc]
...> end)
[{2, {:b, 4}, 6}, {1, {:a, 3}, 5}]
@spec zip_reduce( t(), t(), acc, (enum1_elem :: term(), enum2_elem :: term(), acc -> acc) ) :: acc when acc: term()
縮減兩個列舉,只要任何列舉為空就停止。
在實務上,此函數提供的行為可以用下列方式達成:
Enum.reduce(Stream.zip(left, right), acc, reducer)
但 zip_reduce/4
是為了方便而存在的。
範例
iex> Enum.zip_reduce([1, 2], [3, 4], 0, fn x, y, acc -> x + y + acc end)
10
iex> Enum.zip_reduce([1, 2], [3, 4], [], fn x, y, acc -> [x + y | acc] end)
[6, 4]
將有限集合中對應的列舉元素壓縮成清單,並在過程中使用zip_函數
函數轉換它們。
每個列舉中第一個元素將會放入一個清單中,然後傳遞給一元 zip_fun
函式。接著,每個列舉中的第二個元素會放入一個清單中,並傳遞給 zip_fun
,以此類推,直到 enumerables
中的任何一個列舉用盡元素。
傳回一個清單,其中包含呼叫 zip_fun
的所有結果。
範例
iex> Enum.zip_with([[1, 2], [3, 4], [5, 6]], fn [x, y, z] -> x + y + z end)
[9, 12]
iex> Enum.zip_with([[1, 2], [3, 4]], fn [x, y] -> x + y end)
[4, 6]
將兩個列舉中對應的元素壓縮成清單,並在過程中使用zip_函數
函數轉換它們。
每個集合的對應元素會依序傳遞給提供的二元 zip_fun
函式。傳回一個清單,其中包含對每個元素對呼叫 zip_fun
的結果。
一旦任一列舉用盡元素,就會完成合併。
合併映射
重要的是要記住,合併本質上依賴於順序。如果您合併兩個清單,您將依序取得每個清單中索引的元素。如果我們合併兩個映射,您可能會認為您將取得左邊映射中的給定金鑰和右邊映射中的匹配金鑰,但沒有這樣的保證,因為映射金鑰沒有順序!請考慮以下內容
left = %{:a => 1, 1 => 3}
right = %{:a => 1, :b => :c}
Enum.zip(left, right)
# [{{1, 3}, {:a, 1}}, {{:a, 1}, {:b, :c}}]
如您所見,:a
沒有與 :a
配對。如果您需要這樣,您應該使用 Map.merge/3
。
範例
iex> Enum.zip_with([1, 2], [3, 4], fn x, y -> x + y end)
[4, 6]
iex> Enum.zip_with([1, 2], [3, 4, 5, 6], fn x, y -> x + y end)
[4, 6]
iex> Enum.zip_with([1, 2, 5, 6], [3, 4], fn x, y -> x + y end)
[4, 6]