forked from seven1m/30-days-of-elixir
-
Notifications
You must be signed in to change notification settings - Fork 1
/
04-list.exs
108 lines (90 loc) · 3.08 KB
/
04-list.exs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
# http://elixir-lang.org/getting-started/basic-types.html
ExUnit.start
defmodule ListTest do
use ExUnit.Case
def sample do
["Tim", "Jen", "Mac", "Kai"]
end
test "sigil" do
assert sample == ~w(Tim Jen Mac Kai)
end
test "head" do
[head | _] = sample
assert head == "Tim"
end
test "tail" do
[_ | tail] = sample
assert tail == ~w(Jen Mac Kai)
end
# warning, has to traverse the entire list!
test "last item" do
assert List.last(sample) == "Kai"
end
test "delete item" do
assert List.delete(sample, "Mac") == ~w(Tim Jen Kai)
# only deletes the first occurrence
assert List.delete([1, 2, 2, 3], 2) == [1, 2, 3]
end
test "List.fold" do
list = [20, 10, 5, 2.5]
sum = List.foldr list, 0, &(&1 + &2)
# or...
# sum = List.foldr list, 0, fn (num, sum) -> num + sum end
assert sum == 37.5
end
# Seems that Enum module methods are encouraged over List methods
# (if possible)
test "Enum.reduce" do
list = [20, 10, 5, 2.5]
sum = Enum.reduce list, 0, &(&1 + &2)
# or...
# sum = Enum.reduce list, 0, fn (num, sum) -> num + sum end
assert sum == 37.5
end
# List.wrap is much like Ruby's Array() method
test "wrap" do
assert List.wrap(sample) == sample
assert List.wrap(1) == [1]
assert List.wrap([]) == []
assert List.wrap(nil) == []
end
test "Enum.filter_map" do
some = Enum.filter_map sample, &(String.first(&1) >= "M"), &(&1 <> " Morgan")
assert some == ["Tim Morgan", "Mac Morgan"]
end
test "list comprehension" do
some = for n <- sample, String.first(n) < "M", do: n <> " Morgan"
assert some == ["Jen Morgan", "Kai Morgan"]
end
# I was curious about raw speed of working with large lists...
# Let's just build and reverse a large list.
# Suprisingly, the manual way is not much slower.
# Also got to browse Erlang docs for timer:tc/1
# (http://www.erlang.org/doc/man/timer.html#tc-1) and call thru from Elixir.
# Easy!
test "manual reverse speed" do
{microsec, reversed} = :timer.tc fn -> # Erlang function, yay!
Enum.reduce 1..1_000_000, [], fn (i, l) -> List.insert_at(l, 0, i) end
end
assert reversed == Enum.to_list(1_000_000..1)
IO.puts "manual reverse took #{microsec} microsecs"
end
# Another thing worth pointing out is it's cheap to insert at the front of a
# list while it's expensive to insert at the end of a list (which is O(n)).
test "speed of inserting at the end of a list" do
{microsec, reversed} = :timer.tc fn -> # Erlang function, yay!
# It takes about 1.6 seconds on my laptop even with only 10000 elements.
# For 1..1_000_000, it would take a really long time.
Enum.reduce 1..10000, [], fn (i, l) -> List.insert_at(l, -1, i) end
end
assert reversed == Enum.to_list(1..10000)
IO.puts "inserting at the end of a list took #{microsec} microsecs"
end
test "Enum.reverse speed" do
{microsec, reversed} = :timer.tc fn ->
Enum.reverse 1..1_000_000
end
assert reversed == Enum.to_list(1_000_000..1)
IO.puts "Enum.reverse took #{microsec} microsecs"
end
end