changed
README.md
|
@@ -10,7 +10,7 @@ by adding `panty` to your list of dependencies in `mix.exs`:
|
10
10
|
```elixir
|
11
11
|
def deps do
|
12
12
|
[
|
13
|
- {:panty, "~> 0.1.1"}
|
13
|
+ {:panty, "~> 0.1.3"}
|
14
14
|
]
|
15
15
|
end
|
16
16
|
```
|
changed
hex_metadata.config
|
@@ -16,4 +16,4 @@
|
16
16
|
{<<"optional">>,false},
|
17
17
|
{<<"repository">>,<<"hexpm">>},
|
18
18
|
{<<"requirement">>,<<"~> 0.12.0">>}]]}.
|
19
|
- {<<"version">>,<<"0.1.2">>}.
|
19
|
+ {<<"version">>,<<"0.1.3">>}.
|
changed
lib/collection.ex
|
@@ -3,26 +3,6 @@ defmodule Panty.Collection do
|
3
3
|
Collection utilities
|
4
4
|
"""
|
5
5
|
|
6
|
- @doc """
|
7
|
- Get index of a substring from a pattern.
|
8
|
-
|
9
|
- ## Examples
|
10
|
- iex> Collection.string_find_index("abcdef", "cde")
|
11
|
- 2
|
12
|
- iex> Collection.string_find_index("{% sections 'header' %}", "{% endschema %}")
|
13
|
- nil
|
14
|
-
|
15
|
- """
|
16
|
-
|
17
|
- @spec substring_index(String.t, String.t) :: integer() | nil
|
18
|
-
|
19
|
- def substring_index(pattern, substring) do
|
20
|
- case String.split(pattern, substring, parts: 2) do
|
21
|
- [left, _] -> String.length(left)
|
22
|
- [_] -> nil
|
23
|
- end
|
24
|
- end
|
25
|
-
|
26
6
|
@doc """
|
27
7
|
Get intersection from given lists.
|
28
8
|
|
|
@@ -34,7 +14,7 @@ defmodule Panty.Collection do
|
34
14
|
|
35
15
|
"""
|
36
16
|
|
37
|
- @spec intersection([any()], [any()]) :: [any()]
|
17
|
+ @spec intersection(list(), list()) :: list()
|
38
18
|
|
39
19
|
def intersection(first, second) do
|
40
20
|
first |> Enum.filter(&(Enum.member?(second, &1)))
|
|
@@ -49,7 +29,7 @@ defmodule Panty.Collection do
|
49
29
|
|
50
30
|
"""
|
51
31
|
|
52
|
- @spec initial([any(), ...]) :: [any()]
|
32
|
+ @spec initial(list()) :: list()
|
53
33
|
|
54
34
|
def initial(collection), do: _initial(collection)
|
55
35
|
|
|
@@ -67,7 +47,7 @@ defmodule Panty.Collection do
|
67
47
|
|
68
48
|
"""
|
69
49
|
|
70
|
- @spec compact([any()]) :: [any()]
|
50
|
+ @spec compact(list()) :: list()
|
71
51
|
|
72
52
|
def compact(collection) do
|
73
53
|
Enum.reject(collection, fn
|
|
@@ -88,9 +68,143 @@ defmodule Panty.Collection do
|
88
68
|
|
89
69
|
"""
|
90
70
|
|
91
|
- @spec reject([any()], any()) :: [any()]
|
71
|
+ @spec reject(list(), any()) :: list()
|
92
72
|
|
93
73
|
def reject(collection, pattern) do
|
94
74
|
Enum.reject(collection, fn el -> el == pattern end)
|
95
75
|
end
|
76
|
+
|
77
|
+ @doc """
|
78
|
+ This method is like _.difference except that it accepts iteratee which is invoked for each element of array and values to generate the criterion by which they're compared.
|
79
|
+ The order and references of result values are determined by the first array. The iteratee is invoked with one argument
|
80
|
+
|
81
|
+ ## Examples
|
82
|
+ iex> Collection.difference_by([2.1, 1.2], [2.3, 3.4], &Kernel.round/1)
|
83
|
+ [1.2]
|
84
|
+ iex> Collection.difference_by([%{"x" => 2}, %{"x" => 1}], [%{"x" => 1}], &(&1["x"]))
|
85
|
+ [%{"x" => 2}]
|
86
|
+
|
87
|
+ Iteratee shorthand
|
88
|
+
|
89
|
+ iex> Collection.difference_by([%{"x" => 2}, %{"x" => 1}], [%{"x" => 1}], "x")
|
90
|
+ [%{"x" => 2}]
|
91
|
+ iex> Collection.difference_by([%{x: 2}, %{x: 1}], [%{x: 1}], :x)
|
92
|
+ [%{x: 2}]
|
93
|
+
|
94
|
+ """
|
95
|
+
|
96
|
+ @spec difference_by(list(), list(), (any() -> any())) :: list()
|
97
|
+
|
98
|
+ def difference_by(list, alist, key) when is_bitstring(key) or is_atom(key) do
|
99
|
+ new_alist = alist |> Enum.map(&(&1[key]))
|
100
|
+ list
|
101
|
+ |> Enum.filter(fn el -> !Enum.member?(new_alist, el[key]) end)
|
102
|
+ end
|
103
|
+ def difference_by(list, alist, func) when is_function(func) do
|
104
|
+ new_alist = alist |> Enum.map(&(func.(&1)))
|
105
|
+ list
|
106
|
+ |> Enum.filter(fn el -> !Enum.member?(new_alist, func.(el)) end)
|
107
|
+ end
|
108
|
+
|
109
|
+ @doc """
|
110
|
+ Return a slice of array excluding elements dropped from the end.
|
111
|
+
|
112
|
+ ## Examples
|
113
|
+ iex> Collection.drop_right_while([1, 2, 3, 4, 5], &(&1 == 4))
|
114
|
+ [1, 2, 3]
|
115
|
+ iex> Collection.drop_right_while([%{a: 1, b: 2}, %{a: 2, b: 2}], &(&1.a == 2))
|
116
|
+ [%{a: 1, b: 2}]
|
117
|
+
|
118
|
+ """
|
119
|
+
|
120
|
+ @spec drop_right_while(list(), (... -> boolean)) :: list()
|
121
|
+
|
122
|
+ def drop_right_while(list, func) when is_function(func) do
|
123
|
+ _drop_loop(list, [], func)
|
124
|
+ end
|
125
|
+ def _drop_loop([], acc, _func), do: acc
|
126
|
+ def _drop_loop([h|t], acc, func), do: if func.(h), do: acc, else: _drop_loop(t, acc ++ [h], func)
|
127
|
+
|
128
|
+ @doc """
|
129
|
+ Fills a number of elements of a list with initial value
|
130
|
+
|
131
|
+ ## Examples
|
132
|
+ iex> Collection.fill(5, nil)
|
133
|
+ [nil, nil, nil, nil, nil]
|
134
|
+ iex> Collection.fill(3, "hi")
|
135
|
+ ["hi", "hi", "hi"]
|
136
|
+ """
|
137
|
+
|
138
|
+ @spec fill(integer(), any()) :: [any()]
|
139
|
+
|
140
|
+ def fill(num, val) when is_number(num), do: for _ <- 1..num, do: val
|
141
|
+
|
142
|
+ @doc """
|
143
|
+ Return a map from a list of pairs
|
144
|
+
|
145
|
+ ## Examples
|
146
|
+ iex> Collection.from_pairs([[:a, 1], [:b, 2]])
|
147
|
+ %{a: 1, b: 2}
|
148
|
+ iex > Collection.from_pairs([["vn", "Xin chao"], ["us", "hello"]])
|
149
|
+ %{"us" => "hello", "vn" => "Xin chao"}
|
150
|
+
|
151
|
+ """
|
152
|
+
|
153
|
+ @spec from_pairs(list()) :: map()
|
154
|
+
|
155
|
+ def from_pairs(list) do
|
156
|
+ exc = fn
|
157
|
+ (acc, key, val) when is_bitstring(key) or is_atom(key) -> Map.put(acc, key, val)
|
158
|
+ (_, _, _) -> throw("Key must be a string or atom.")
|
159
|
+ end
|
160
|
+ Enum.reduce(list, %{}, fn ([key, val], acc) -> exc.(acc, key, val) end)
|
161
|
+ end
|
162
|
+
|
163
|
+ @doc """
|
164
|
+ Find index from right to left.
|
165
|
+
|
166
|
+ ## Examples
|
167
|
+ iex> Collection.last_index_of([1, 1, 3, 4, 2], 4)
|
168
|
+ 3
|
169
|
+ iex> Collection.last_index_of([1, 9, 3, 1, 2], 4)
|
170
|
+ nil
|
171
|
+
|
172
|
+ """
|
173
|
+
|
174
|
+ @spec last_index_of(list(), any()) :: integer()
|
175
|
+
|
176
|
+ def last_index_of(list, el) do
|
177
|
+ list
|
178
|
+ |> Enum.reverse()
|
179
|
+ |> Enum.find_index(&(&1 == el))
|
180
|
+ |> case do
|
181
|
+ nil -> nil
|
182
|
+ idx -> length(list) - idx - 1
|
183
|
+ end
|
184
|
+ end
|
185
|
+
|
186
|
+ @doc """
|
187
|
+ Same as `last_index_of/2` but search from the index.
|
188
|
+
|
189
|
+ ## Examples
|
190
|
+ iex> Collection.last_index_of([1, 1, 3, 4, 2], 4, 2)
|
191
|
+ 3
|
192
|
+ iex> Collection.last_index_of("abbcd" |> String.graphemes, "b", 3)
|
193
|
+ nil
|
194
|
+
|
195
|
+ """
|
196
|
+
|
197
|
+ @spec last_index_of(list(), any(), integer) :: integer()
|
198
|
+
|
199
|
+ def last_index_of(list, el, from) do
|
200
|
+ list = list |> Enum.drop(from)
|
201
|
+
|
202
|
+ list
|
203
|
+ |> Enum.reverse()
|
204
|
+ |> Enum.find_index(&(&1 == el))
|
205
|
+ |> case do
|
206
|
+ nil -> nil
|
207
|
+ idx -> length(list) - idx - 1 + from
|
208
|
+ end
|
209
|
+ end
|
96
210
|
end
|
|
\ No newline at end of file
|
changed
lib/panty.ex
|
@@ -1,5 +1,5 @@
|
1
1
|
defmodule Panty do
|
2
2
|
@moduledoc """
|
3
|
- Documentation for Panty.
|
3
|
+ Documentation for Panty - an utility library for elixir.
|
4
4
|
"""
|
5
5
|
end
|
changed
lib/string.ex
|
@@ -52,4 +52,25 @@ defmodule Panty.String do
|
52
52
|
|> Enum.join("-")
|
53
53
|
|> String.downcase
|
54
54
|
end
|
55
|
+
|
56
|
+
|
57
|
+ @doc """
|
58
|
+ Get index of a substring from a pattern.
|
59
|
+
|
60
|
+ ## Examples
|
61
|
+ iex> Collection.string_find_index("abcdef", "cde")
|
62
|
+ 2
|
63
|
+ iex> Collection.string_find_index("{% sections 'header' %}", "{% endschema %}")
|
64
|
+ nil
|
65
|
+
|
66
|
+ """
|
67
|
+
|
68
|
+ @spec substring_index(String.t, String.t) :: integer() | nil
|
69
|
+
|
70
|
+ def substring_index(pattern, substring) do
|
71
|
+ case String.split(pattern, substring, parts: 2) do
|
72
|
+ [left, _] -> String.length(left)
|
73
|
+ [_] -> nil
|
74
|
+ end
|
75
|
+ end
|
55
76
|
end
|
|
\ No newline at end of file
|
changed
mix.exs
|
@@ -5,7 +5,7 @@ defmodule Panty.Mixfile do
|
5
5
|
[
|
6
6
|
app: :panty,
|
7
7
|
name: "Panty",
|
8
|
- version: "0.1.2",
|
8
|
+ version: "0.1.3",
|
9
9
|
elixir: "~> 1.2",
|
10
10
|
start_permanent: Mix.env == :prod,
|
11
11
|
description: description(),
|