Skip to content

Commit de1d47f

Browse files
author
José Valim
committed
Add Enum.at/2, Enum.at/3 and Enum.fetch/2
1 parent 1051b61 commit de1d47f

File tree

2 files changed

+84
-18
lines changed

2 files changed

+84
-18
lines changed

lib/elixir/lib/enum.ex

Lines changed: 71 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ defmodule Enum do
8585
@type t :: Enum.Iterator.t
8686
@type element :: any
8787
@type index :: non_neg_integer
88+
@type default :: any
8889

8990
@doc """
9091
Returns true if the `collection` is empty, otherwise false.
@@ -233,6 +234,34 @@ defmodule Enum do
233234
Raises out of bounds error in case the given position
234235
is outside the range of the collection.
235236
237+
Expects an ordered collection.
238+
239+
## Examples
240+
241+
iex> Enum.at([2,4,6], 0)
242+
2
243+
iex> Enum.at([2,4,6], 2)
244+
6
245+
iex> Enum.at([2,4,6], 4)
246+
nil
247+
iex> Enum.at([2,4,6], 4, :none)
248+
:none
249+
250+
"""
251+
@spec at(t, index) :: element | nil
252+
@spec at(t, index, default) :: element | default
253+
def at(collection, n, default // nil) when n >= 0 do
254+
case fetch(collection, n) do
255+
{ :ok, h } -> h
256+
:error -> default
257+
end
258+
end
259+
260+
@doc """
261+
Finds the element at the given index (zero-based).
262+
Raises out of bounds error in case the given position
263+
is outside the range of the collection.
264+
236265
Expects an ordered collection.
237266
238267
## Examples
@@ -246,16 +275,10 @@ defmodule Enum do
246275
247276
"""
248277
@spec at!(t, index) :: element | no_return
249-
def at!(collection, n) when is_list(collection) and n >= 0 do
250-
do_at!(collection, n)
251-
end
252-
253278
def at!(collection, n) when n >= 0 do
254-
case I.iterator(collection) do
255-
{ iterator, pointer } ->
256-
do_at!(pointer, iterator, n)
257-
list when is_list(list) ->
258-
do_at!(list, n)
279+
case fetch(collection, n) do
280+
{ :ok, h } -> h
281+
:error -> raise Enum.OutOfBoundsError
259282
end
260283
end
261284

@@ -468,6 +491,36 @@ defmodule Enum do
468491
end
469492
end
470493

494+
@doc """
495+
Finds the element at the given index (zero-based).
496+
Returns `{ :ok, element }` if found, otherwise `:error`.
497+
498+
Expects an ordered collection.
499+
500+
## Examples
501+
502+
iex> Enum.fetch([2,4,6], 0)
503+
{ :ok, 2 }
504+
iex> Enum.fetch([2,4,6], 2)
505+
{ :ok, 6 }
506+
iex> Enum.fetch([2,4,6], 4)
507+
:error
508+
509+
"""
510+
@spec fetch(t, index) :: { :ok, element } | :error
511+
def fetch(collection, n) when is_list(collection) and n >= 0 do
512+
do_fetch(collection, n)
513+
end
514+
515+
def fetch(collection, n) when n >= 0 do
516+
case I.iterator(collection) do
517+
{ iterator, pointer } ->
518+
do_fetch(pointer, iterator, n)
519+
list when is_list(list) ->
520+
do_fetch(list, n)
521+
end
522+
end
523+
471524
@doc """
472525
Filters the collection, i.e. returns only those elements
473526
for which `fun` returns true.
@@ -531,8 +584,8 @@ defmodule Enum do
531584
3
532585
533586
"""
534-
@spec find(t, (element -> any)) :: element | :nil
535-
@spec find(t, any, (element -> any)) :: element | :nil
587+
@spec find(t, (element -> any)) :: element | nil
588+
@spec find(t, default, (element -> any)) :: element | default
536589

537590
def find(collection, ifnone // nil, fun)
538591

@@ -1277,15 +1330,15 @@ defmodule Enum do
12771330
false
12781331
end
12791332

1280-
## at!
1333+
## fetch
12811334

1282-
defp do_at!([h|_], 0), do: h
1283-
defp do_at!([_|t], n), do: do_at!(t, n - 1)
1284-
defp do_at!([], _), do: raise Enum.OutOfBoundsError
1335+
defp do_fetch([h|_], 0), do: { :ok, h }
1336+
defp do_fetch([_|t], n), do: do_fetch(t, n - 1)
1337+
defp do_fetch([], _), do: :error
12851338

1286-
defp do_at!({ h, _next }, _iterator, 0), do: h
1287-
defp do_at!({ _, next }, iterator, n), do: do_at!(iterator.(next), iterator, n - 1)
1288-
defp do_at!(:stop, _iterator, _), do: raise Enum.OutOfBoundsError
1339+
defp do_fetch({ h, _next }, _iterator, 0), do: { :ok, h }
1340+
defp do_fetch({ _, next }, iterator, n), do: do_fetch(iterator.(next), iterator, n - 1)
1341+
defp do_fetch(:stop, _iterator, _), do: :error
12891342

12901343
## count
12911344

lib/elixir/test/elixir/enum_test.exs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,13 @@ defmodule EnumTest.List do
4747
refute Enum.any?([])
4848
end
4949

50+
test :at do
51+
assert Enum.at([2,4,6], 0) == 2
52+
assert Enum.at([2,4,6], 2) == 6
53+
assert Enum.at([2,4,6], 4) == nil
54+
assert Enum.at([2,4,6], 4, :none) == :none
55+
end
56+
5057
test :at! do
5158
assert Enum.at!([2,4,6], 0) == 2
5259
assert Enum.at!([2,4,6], 2) == 6
@@ -128,6 +135,12 @@ defmodule EnumTest.List do
128135
end
129136
end
130137

138+
test :fetch do
139+
assert Enum.fetch([2,4,6], 0) == { :ok, 2 }
140+
assert Enum.fetch([2,4,6], 2) == { :ok, 6 }
141+
assert Enum.fetch([2,4,6], 4) == :error
142+
end
143+
131144
test :first do
132145
assert Enum.first([]) == nil
133146
assert Enum.first([1,2,3]) == 1

0 commit comments

Comments
 (0)