Skip to content

Commit ba20926

Browse files
author
José Valim
committed
Merge pull request #1675 from ericmj/enum-at-fetch-neg
Support negative indicies in Enum.at/fetch/fetch!
2 parents 4d3a832 + 80ae944 commit ba20926

File tree

2 files changed

+27
-6
lines changed

2 files changed

+27
-6
lines changed

lib/elixir/lib/enum.ex

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -226,9 +226,9 @@ defmodule Enum do
226226
:none
227227
228228
"""
229-
@spec at(t, index) :: element | nil
230-
@spec at(t, index, default) :: element | default
231-
def at(collection, n, default // nil) when n >= 0 do
229+
@spec at(t, integer) :: element | nil
230+
@spec at(t, integer, default) :: element | default
231+
def at(collection, n, default // nil) do
232232
case fetch(collection, n) do
233233
{ :ok, h } -> h
234234
:error -> default
@@ -398,7 +398,7 @@ defmodule Enum do
398398
:error
399399
400400
"""
401-
@spec fetch(t, index) :: { :ok, element } | :error
401+
@spec fetch(t, integer) :: { :ok, element } | :error
402402
def fetch(collection, n) when is_list(collection) and n >= 0 do
403403
do_fetch(collection, n)
404404
end
@@ -417,6 +417,11 @@ defmodule Enum do
417417
{ :enum_fetch, entry } -> { :ok, entry }
418418
end
419419

420+
def fetch(collection, n) when n < 0 do
421+
{ list, count } = iterate_and_count_oob(collection, n)
422+
if count >= 0, do: fetch(list, count), else: :error
423+
end
424+
420425
@doc """
421426
Finds the element at the given index (zero-based).
422427
Raises `OutOfBoundsError` if the given position
@@ -434,8 +439,8 @@ defmodule Enum do
434439
** (Enum.OutOfBoundsError) out of bounds error
435440
436441
"""
437-
@spec fetch!(t, index) :: element | no_return
438-
def fetch!(collection, n) when n >= 0 do
442+
@spec fetch!(t, integer) :: element | no_return
443+
def fetch!(collection, n) do
439444
case fetch(collection, n) do
440445
{ :ok, h } -> h
441446
:error -> raise Enum.OutOfBoundsError

lib/elixir/test/elixir/enum_test.exs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@ defmodule EnumTest.List do
5252
assert Enum.at([2, 4, 6], 2) == 6
5353
assert Enum.at([2, 4, 6], 4) == nil
5454
assert Enum.at([2, 4, 6], 4, :none) == :none
55+
assert Enum.at([2, 4, 6], -2) == 4
56+
assert Enum.at([2, 4, 6], -4) == nil
5557
end
5658

5759
test :concat_1 do
@@ -78,9 +80,15 @@ defmodule EnumTest.List do
7880
test :fetch! do
7981
assert Enum.fetch!([2, 4, 6], 0) == 2
8082
assert Enum.fetch!([2, 4, 6], 2) == 6
83+
assert Enum.fetch!([2, 4, 6], -2) == 4
84+
8185
assert_raise Enum.OutOfBoundsError, fn ->
8286
Enum.fetch!([2, 4, 6], 4)
8387
end
88+
89+
assert_raise Enum.OutOfBoundsError, fn ->
90+
Enum.fetch!([2, 4, 6], -4)
91+
end
8492
end
8593

8694
test :drop do
@@ -129,6 +137,8 @@ defmodule EnumTest.List do
129137
assert Enum.fetch([2, 4, 6], 0) == { :ok, 2 }
130138
assert Enum.fetch([2, 4, 6], 2) == { :ok, 6 }
131139
assert Enum.fetch([2, 4, 6], 4) == :error
140+
assert Enum.fetch([2, 4, 6], -2) == { :ok, 4}
141+
assert Enum.fetch([2, 4, 6], -4) == :error
132142
end
133143

134144
test :first do
@@ -379,6 +389,8 @@ defmodule EnumTest.Range do
379389
test :fetch! do
380390
assert Enum.fetch!(2..6, 0) == 2
381391
assert Enum.fetch!(2..6, 4) == 6
392+
assert Enum.fetch!(2..6, -1) == 6
393+
assert Enum.fetch!(2..6, -2) == 5
382394
assert Enum.fetch!(-2..-6, 0) == -2
383395
assert Enum.fetch!(-2..-6, 4) == -6
384396

@@ -389,6 +401,10 @@ defmodule EnumTest.Range do
389401
assert_raise Enum.OutOfBoundsError, fn ->
390402
assert Enum.fetch!(-2..-6, 8)
391403
end
404+
405+
assert_raise Enum.OutOfBoundsError, fn ->
406+
assert Enum.fetch!(2..6, -8)
407+
end
392408
end
393409

394410
test :count do

0 commit comments

Comments
 (0)