@@ -27,8 +27,14 @@ defmodule Enum do
27
27
@ type index :: integer
28
28
@ type element :: any
29
29
30
+ @ type default :: any
31
+
30
32
require Stream.Reducers , as: R
31
33
34
+ defmacrop skip ( acc ) do
35
+ acc
36
+ end
37
+
32
38
defmacrop next ( _ , entry , acc ) do
33
39
quote ( do: [ unquote ( entry ) | unquote ( acc ) ] )
34
40
end
@@ -53,14 +59,132 @@ defmodule Enum do
53
59
Enumerable . reduce ( enumerable , { :cont , acc } , fn x , acc -> { :cont , fun . ( x , acc ) } end ) |> elem ( 1 )
54
60
end
55
61
62
+ @ doc """
63
+ Returns `true` if `fun.(element)` is truthy for all elements in `enumerable`.
64
+
65
+ Iterates over the `enumerable` and invokes `fun` on each element. When an invocation
66
+ of `fun` returns a falsy value (`false` or `nil`) iteration stops immediately and
67
+ `false` is returned. In all other cases `true` is returned.
68
+
69
+ ## Examples
70
+
71
+ iex> Enum.all?([2, 4, 6], fn x -> rem(x, 2) == 0 end)
72
+ true
73
+
74
+ iex> Enum.all?([2, 3, 4], fn x -> rem(x, 2) == 0 end)
75
+ false
76
+
77
+ iex> Enum.all?([], fn x -> x > 0 end)
78
+ true
79
+
80
+ If no function is given, the truthiness of each element is checked during iteration.
81
+ When an element has a falsy value (`false` or `nil`) iteration stops immediately and
82
+ `false` is returned. In all other cases `true` is returned.
83
+
84
+ iex> Enum.all?([1, 2, 3])
85
+ true
86
+
87
+ iex> Enum.all?([1, nil, 3])
88
+ false
89
+
90
+ iex> Enum.all?([])
91
+ true
92
+
93
+ """
94
+ @ spec all? ( t , ( element -> as_boolean ( term ) ) ) :: boolean
95
+
96
+ def all? ( enumerable , fun \\ fn x -> x end )
97
+
56
98
def all? ( enumerable , fun ) when is_list ( enumerable ) do
57
99
all_list ( enumerable , fun )
58
100
end
59
101
102
+ def all? ( enumerable , fun ) do
103
+ Enumerable . reduce ( enumerable , { :cont , true } , fn entry , _ ->
104
+ if fun . ( entry ) , do: { :cont , true } , else: { :halt , false }
105
+ end )
106
+ |> elem ( 1 )
107
+ end
108
+
109
+ @ doc """
110
+ Returns `true` if `fun.(element)` is truthy for at least one element in `enumerable`.
111
+
112
+ Iterates over the `enumerable` and invokes `fun` on each element. When an invocation
113
+ of `fun` returns a truthy value (neither `false` nor `nil`) iteration stops
114
+ immediately and `true` is returned. In all other cases `false` is returned.
115
+
116
+ ## Examples
117
+
118
+ iex> Enum.any?([2, 4, 6], fn x -> rem(x, 2) == 1 end)
119
+ false
120
+
121
+ iex> Enum.any?([2, 3, 4], fn x -> rem(x, 2) == 1 end)
122
+ true
123
+
124
+ iex> Enum.any?([], fn x -> x > 0 end)
125
+ false
126
+
127
+ If no function is given, the truthiness of each element is checked during iteration.
128
+ When an element has a truthy value (neither `false` nor `nil`) iteration stops
129
+ immediately and `true` is returned. In all other cases `false` is returned.
130
+
131
+ iex> Enum.any?([false, false, false])
132
+ false
133
+
134
+ iex> Enum.any?([false, true, false])
135
+ true
136
+
137
+ iex> Enum.any?([])
138
+ false
139
+
140
+ """
141
+ @ spec any? ( t , ( element -> as_boolean ( term ) ) ) :: boolean
142
+
143
+ def any? ( enumerable , fun \\ fn x -> x end )
144
+
60
145
def any? ( enumerable , fun ) when is_list ( enumerable ) do
61
146
any_list ( enumerable , fun )
62
147
end
63
148
149
+ def any? ( enumerable , fun ) do
150
+ Enumerable . reduce ( enumerable , { :cont , false } , fn entry , _ ->
151
+ if fun . ( entry ) , do: { :halt , true } , else: { :cont , false }
152
+ end )
153
+ |> elem ( 1 )
154
+ end
155
+
156
+ @ doc """
157
+ Finds the element at the given `index` (zero-based).
158
+
159
+ Returns `default` if `index` is out of bounds.
160
+
161
+ A negative `index` can be passed, which means the `enumerable` is
162
+ enumerated once and the `index` is counted from the end (for example,
163
+ `-1` finds the last element).
164
+
165
+ ## Examples
166
+
167
+ iex> Enum.at([2, 4, 6], 0)
168
+ 2
169
+
170
+ iex> Enum.at([2, 4, 6], 2)
171
+ 6
172
+
173
+ iex> Enum.at([2, 4, 6], 4)
174
+ nil
175
+
176
+ iex> Enum.at([2, 4, 6], 4, :none)
177
+ :none
178
+
179
+ """
180
+ @ spec at ( t , index , default ) :: element | default
181
+ def at ( enumerable , index , default \\ nil ) when is_integer ( index ) do
182
+ case slice_any ( enumerable , index , 1 ) do
183
+ [ value ] -> value
184
+ [ ] -> default
185
+ end
186
+ end
187
+
64
188
@ doc """
65
189
Returns the size of the enumerable.
66
190
@@ -85,19 +209,102 @@ defmodule Enum do
85
209
end
86
210
end
87
211
212
+ @ doc """
213
+ Invokes the given `fun` for each element in the `enumerable`.
214
+
215
+ Returns `:ok`.
216
+
217
+ ## Examples
218
+
219
+ Enum.each(["some", "example"], fn x -> IO.puts(x) end)
220
+ "some"
221
+ "example"
222
+ #=> :ok
223
+
224
+ """
225
+ @ spec each ( t , ( element -> any ) ) :: :ok
88
226
def each ( enumerable , fun ) when is_list ( enumerable ) do
89
227
:lists . foreach ( fun , enumerable )
90
228
:ok
91
229
end
92
230
231
+ def each ( enumerable , fun ) do
232
+ reduce ( enumerable , nil , fn entry , _ ->
233
+ fun . ( entry )
234
+ nil
235
+ end )
236
+
237
+ :ok
238
+ end
239
+
240
+ @ doc """
241
+ Filters the `enumerable`, i.e. returns only those elements
242
+ for which `fun` returns a truthy value.
243
+
244
+ See also `reject/2` which discards all elements where the
245
+ function returns a truthy value.
246
+
247
+ ## Examples
248
+
249
+ iex> Enum.filter([1, 2, 3], fn x -> rem(x, 2) == 0 end)
250
+ [2]
251
+
252
+ Keep in mind that `filter` is not capable of filtering and
253
+ transforming an element at the same time. If you would like
254
+ to do so, consider using `flat_map/2`. For example, if you
255
+ want to convert all strings that represent an integer and
256
+ discard the invalid one in one pass:
257
+
258
+ strings = ["1234", "abc", "12ab"]
259
+
260
+ Enum.flat_map(strings, fn string ->
261
+ case Integer.parse(string) do
262
+ # transform to integer
263
+ {int, _rest} -> [int]
264
+ # skip the value
265
+ :error -> []
266
+ end
267
+ end)
268
+
269
+ """
270
+ @ spec filter ( t , ( element -> as_boolean ( term ) ) ) :: list
93
271
def filter ( enumerable , fun ) when is_list ( enumerable ) do
94
272
filter_list ( enumerable , fun )
95
273
end
96
274
275
+ def filter ( enumerable , fun ) do
276
+ reduce ( enumerable , [ ] , R . filter ( fun ) ) |> :lists . reverse ( )
277
+ end
278
+
279
+ @ doc """
280
+ Returns the first element for which `fun` returns a truthy value.
281
+ If no such element is found, returns `default`.
282
+
283
+ ## Examples
284
+
285
+ iex> Enum.find([2, 3, 4], fn x -> rem(x, 2) == 1 end)
286
+ 3
287
+
288
+ iex> Enum.find([2, 4, 6], fn x -> rem(x, 2) == 1 end)
289
+ nil
290
+ iex> Enum.find([2, 4, 6], 0, fn x -> rem(x, 2) == 1 end)
291
+ 0
292
+
293
+ """
294
+ @ spec find ( t , default , ( element -> any ) ) :: element | default
295
+ def find ( enumerable , default \\ nil , fun )
296
+
97
297
def find ( enumerable , default , fun ) when is_list ( enumerable ) do
98
298
find_list ( enumerable , default , fun )
99
299
end
100
300
301
+ def find ( enumerable , default , fun ) do
302
+ Enumerable . reduce ( enumerable , { :cont , default } , fn entry , default ->
303
+ if fun . ( entry ) , do: { :halt , entry } , else: { :cont , default }
304
+ end )
305
+ |> elem ( 1 )
306
+ end
307
+
101
308
def find_index ( enumerable , fun ) when is_list ( enumerable ) do
102
309
find_index_list ( enumerable , 0 , fun )
103
310
end
@@ -389,12 +596,12 @@ defmodule Enum do
389
596
end
390
597
391
598
@ doc """
392
- Joins the given enumerable into a binary using `joiner` as a
599
+ Joins the given ` enumerable` into a binary using `joiner` as a
393
600
separator.
394
601
395
602
If `joiner` is not passed at all, it defaults to the empty binary.
396
603
397
- All items in the enumerable must be convertible to a binary,
604
+ All elements in the ` enumerable` must be convertible to a binary,
398
605
otherwise an error is raised.
399
606
400
607
## Examples
@@ -409,6 +616,12 @@ defmodule Enum do
409
616
@ spec join ( t , String . t ( ) ) :: String . t ( )
410
617
def join ( enumerable , joiner \\ "" )
411
618
619
+ def join ( enumerable , "" ) do
620
+ enumerable
621
+ |> map ( & entry_to_string ( & 1 ) )
622
+ |> IO . iodata_to_binary ( )
623
+ end
624
+
412
625
def join ( enumerable , joiner ) when is_binary ( joiner ) do
413
626
reduced =
414
627
reduce ( enumerable , :first , fn
@@ -610,6 +823,7 @@ defmodule Enum do
610
823
@ compile { :inline , entry_to_string: 1 , reduce: 3 }
611
824
612
825
defp entry_to_string ( entry ) when is_binary ( entry ) , do: entry
826
+ defp entry_to_string ( entry ) , do: String.Chars . to_string ( entry )
613
827
614
828
## drop
615
829
0 commit comments