Skip to content

Commit 263f4bf

Browse files
committed
Add Enum.slice/3
1 parent 3768087 commit 263f4bf

File tree

2 files changed

+70
-0
lines changed

2 files changed

+70
-0
lines changed

lib/elixir/lib/enum.ex

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1303,6 +1303,38 @@ defmodule Enum do
13031303
end
13041304
end
13051305

1306+
@doc """
1307+
Returns a subset list of the given collection. Dropping elements
1308+
until element position `start`, then taking `count` elements.
1309+
Expects an ordered collection.
1310+
"""
1311+
@spec slice(t, integer, integer) :: list
1312+
1313+
def slice(_coll, _start, 0), do: []
1314+
1315+
def slice(coll, start, count) when is_list(coll) and start >= 0 do
1316+
do_slice(coll, start, count)
1317+
end
1318+
1319+
def slice(coll, start, count) when start >= 0 do
1320+
{ _, _, list } = Enumerable.reduce(coll, { start, count, [] }, fn
1321+
_entry, { start, count, _list } when start > 0 ->
1322+
{ start-1, count, [] }
1323+
entry, { start, count, list } when count > 1 ->
1324+
{ start, count-1, [entry|list] }
1325+
entry, { _start, _count, list } ->
1326+
throw { :enum_slice, [entry|list] }
1327+
end)
1328+
:lists.reverse(list)
1329+
catch
1330+
{ :enum_slice, list } -> :lists.reverse(list)
1331+
end
1332+
1333+
def slice(coll, start, count) when start < 0 do
1334+
{ list, start } = iterate_and_count(coll, start)
1335+
slice(list, start, count)
1336+
end
1337+
13061338
## Helpers
13071339

13081340
@compile { :inline, chunks_n: 5, chunks_step: 4, to_string: 2 }
@@ -1645,6 +1677,20 @@ defmodule Enum do
16451677

16461678
defp do_zip_next([h|t]), do: { h, t }
16471679
defp do_zip_next([]), do: { nil, [] }
1680+
1681+
## slice
1682+
1683+
defp do_slice([], _start, _count), do: []
1684+
1685+
defp do_slice(_list, _start, 0), do: []
1686+
1687+
defp do_slice([h|t], 0, count) do
1688+
[h|do_slice(t, 0, count-1)]
1689+
end
1690+
1691+
defp do_slice([_|t], start, count) do
1692+
do_slice(t, start-1, count)
1693+
end
16481694
end
16491695

16501696
defimpl Enumerable, for: List do

lib/elixir/test/elixir/enum_test.exs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,18 @@ defmodule EnumTest.List do
311311
assert Enum.chunks_by([], fn _ -> true end) == []
312312
assert Enum.chunks_by([1], fn _ -> true end) == [[1]]
313313
end
314+
315+
test :slice do
316+
assert Enum.slice([1,2,3,4,5], 0, 0) == []
317+
assert Enum.slice([1,2,3,4,5], 0, 1) == [1]
318+
assert Enum.slice([1,2,3,4,5], 0, 2) == [1, 2]
319+
assert Enum.slice([1,2,3,4,5], 1, 2) == [2, 3]
320+
assert Enum.slice([1,2,3,4,5], 1, 0) == []
321+
assert Enum.slice([1,2,3,4,5], 2, 5) == [3, 4, 5]
322+
assert Enum.slice([1,2,3,4,5], 5, 5) == []
323+
assert Enum.slice([1,2,3,4,5], -2, 5) == [4, 5]
324+
assert Enum.slice([1,2,3,4,5], -3, 1) == [3]
325+
end
314326
end
315327

316328
defmodule EnumTest.Range do
@@ -653,6 +665,18 @@ defmodule EnumTest.Range do
653665
assert Enum.chunks_by(1..4, fn _ -> true end) == [[1, 2, 3, 4]]
654666
assert Enum.chunks_by(1..4, &(rem(&1, 2) == 1)) == [[1], [2], [3], [4]]
655667
end
668+
669+
test :slice do
670+
assert Enum.slice(1..5, 0, 0) == []
671+
assert Enum.slice(1..5, 0, 1) == [1]
672+
assert Enum.slice(1..5, 0, 2) == [1, 2]
673+
assert Enum.slice(1..5, 1, 2) == [2, 3]
674+
assert Enum.slice(1..5, 1, 0) == []
675+
assert Enum.slice(1..5, 2, 5) == [3, 4, 5]
676+
assert Enum.slice(1..5, 5, 5) == []
677+
assert Enum.slice(1..5, -2, 5) == [4, 5]
678+
assert Enum.slice(1..5, -3, 1) == [3]
679+
end
656680
end
657681

658682
defmodule EnumTest.Others do

0 commit comments

Comments
 (0)