gandora-std 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- gandora_std-0.1.0/.gitignore +19 -0
- gandora_std-0.1.0/PKG-INFO +5 -0
- gandora_std-0.1.0/gandora.jsonc +8 -0
- gandora_std-0.1.0/pkg/gandora_std/_gan/gandora_std/enum.gan +222 -0
- gandora_std-0.1.0/pkg/gandora_std/_gan/gandora_std/keyword.gan +43 -0
- gandora_std-0.1.0/pkg/gandora_std/_gan/gandora_std/list.gan +72 -0
- gandora_std-0.1.0/pkg/gandora_std/_gan/gandora_std/map.gan +91 -0
- gandora_std-0.1.0/pkg/gandora_std/_gan/gandora_std/string.gan +117 -0
- gandora_std-0.1.0/pkg/gandora_std/enum.py +278 -0
- gandora_std-0.1.0/pkg/gandora_std/gandora.toml +27 -0
- gandora_std-0.1.0/pkg/gandora_std/keyword.py +82 -0
- gandora_std-0.1.0/pkg/gandora_std/list.py +83 -0
- gandora_std-0.1.0/pkg/gandora_std/map.py +116 -0
- gandora_std-0.1.0/pkg/gandora_std/string.py +147 -0
- gandora_std-0.1.0/pyproject.toml +19 -0
- gandora_std-0.1.0/src/enum.gan +222 -0
- gandora_std-0.1.0/src/keyword.gan +43 -0
- gandora_std-0.1.0/src/list.gan +72 -0
- gandora_std-0.1.0/src/map.gan +91 -0
- gandora_std-0.1.0/src/string.gan +117 -0
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# Python-generated files
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[oc]
|
|
4
|
+
/build/
|
|
5
|
+
dist/
|
|
6
|
+
wheels/
|
|
7
|
+
*.egg-info
|
|
8
|
+
.pytest_cache/
|
|
9
|
+
.mypy_cache/
|
|
10
|
+
.ruff_cache/
|
|
11
|
+
.gandora/
|
|
12
|
+
|
|
13
|
+
# Virtual environments
|
|
14
|
+
.venv/
|
|
15
|
+
|
|
16
|
+
# Rust-generated files
|
|
17
|
+
/target/
|
|
18
|
+
|
|
19
|
+
.env
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
defmodule Enum do
|
|
2
|
+
@moduledoc "Eager, data-first collection functions (GEP-0010). Every subject comes first, so everything pipes."
|
|
3
|
+
@moduledoc_trans zh_CN: "急切求值、数据优先的集合函数(GEP-0010)。主语在首位,全部可入管道。"
|
|
4
|
+
|
|
5
|
+
@doc "Applies `f` to every element."
|
|
6
|
+
@doc_trans zh_CN: "对每个元素应用 `f`。"
|
|
7
|
+
@example """
|
|
8
|
+
gan> Enum.map([1, 2, 3], fn x -> x * 10 end)
|
|
9
|
+
[10, 20, 30]
|
|
10
|
+
"""
|
|
11
|
+
def map(xs, f), do: :builtins.list(:builtins.map(f, xs))
|
|
12
|
+
|
|
13
|
+
@doc "Keeps elements for which `f` is truthy."
|
|
14
|
+
@doc_trans zh_CN: "保留 `f` 为真值的元素。"
|
|
15
|
+
@example """
|
|
16
|
+
gan> Enum.filter([1, 2, 3, 4], fn x -> rem(x, 2) == 0 end)
|
|
17
|
+
[2, 4]
|
|
18
|
+
"""
|
|
19
|
+
def filter(xs, f), do: ~python([x for x in <%= xs %> if <%= f %>(x)])
|
|
20
|
+
|
|
21
|
+
@doc "Drops elements for which `f` is truthy."
|
|
22
|
+
@doc_trans zh_CN: "丢弃 `f` 为真值的元素。"
|
|
23
|
+
def reject(xs, f), do: ~python([x for x in <%= xs %> if not <%= f %>(x)])
|
|
24
|
+
|
|
25
|
+
@doc "Folds left with Elixir argument order: `f` receives (element, acc)."
|
|
26
|
+
@doc_trans zh_CN: "左折叠,参数顺序与 Elixir 一致:`f` 接收 (元素, 累积值)。"
|
|
27
|
+
@example """
|
|
28
|
+
gan> Enum.reduce([1, 2, 3, 4], 0, fn x, acc -> acc + x end)
|
|
29
|
+
10
|
|
30
|
+
"""
|
|
31
|
+
def reduce(xs, acc, f) do
|
|
32
|
+
:functools.reduce(fn a, x -> f.(x, a) end, xs, acc)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
@doc "Sum of the elements."
|
|
36
|
+
@doc_trans zh_CN: "元素之和。"
|
|
37
|
+
def sum(xs), do: :builtins.sum(xs)
|
|
38
|
+
|
|
39
|
+
@doc "Number of elements."
|
|
40
|
+
@doc_trans zh_CN: "元素个数。"
|
|
41
|
+
def count(xs), do: :builtins.len(xs)
|
|
42
|
+
|
|
43
|
+
@doc "Ascending sort."
|
|
44
|
+
@doc_trans zh_CN: "升序排序。"
|
|
45
|
+
def sort(xs), do: :builtins.sorted(xs)
|
|
46
|
+
|
|
47
|
+
@doc "Sorts by the key computed by `f` (Python `key=`, not a comparator)."
|
|
48
|
+
@doc_trans zh_CN: "按 `f` 计算的键排序(Python 的 `key=`,非比较器)。"
|
|
49
|
+
@example """
|
|
50
|
+
gan> Enum.sort_by(["ccc", "a", "bb"], fn s -> String.length(s) end)
|
|
51
|
+
['a', 'bb', 'ccc']
|
|
52
|
+
"""
|
|
53
|
+
def sort_by(xs, f), do: :builtins.sorted(xs, key: f)
|
|
54
|
+
|
|
55
|
+
@doc "Elements in reverse order."
|
|
56
|
+
@doc_trans zh_CN: "逆序排列的元素。"
|
|
57
|
+
def reverse(xs), do: ~python(list(reversed(<%= xs %>)))
|
|
58
|
+
|
|
59
|
+
@doc "Joins elements (converted by `to_string`) with `sep`."
|
|
60
|
+
@doc_trans zh_CN: "以 `sep` 连接各元素(先经 `to_string` 转换)。"
|
|
61
|
+
@example """
|
|
62
|
+
gan> Enum.join([1, 2, 3], "-")
|
|
63
|
+
'1-2-3'
|
|
64
|
+
"""
|
|
65
|
+
def join(xs, sep), do: sep.join(~python([str(x) for x in <%= xs %>]))
|
|
66
|
+
|
|
67
|
+
@doc "The element at `index` (negative counts from the end), or nil."
|
|
68
|
+
@doc_trans zh_CN: "位于 `index` 的元素(负数从尾部数起),越界返回 nil。"
|
|
69
|
+
def at(xs, index) do
|
|
70
|
+
if index < :builtins.len(xs) and index >= -:builtins.len(xs) do
|
|
71
|
+
~python(<%= xs %>[<%= index %>])
|
|
72
|
+
else
|
|
73
|
+
nil
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
@doc "The first `n` elements."
|
|
78
|
+
@doc_trans zh_CN: "前 `n` 个元素。"
|
|
79
|
+
def take(xs, n), do: ~python(<%= xs %>[:<%= n %>])
|
|
80
|
+
|
|
81
|
+
@doc "The elements after the first `n`."
|
|
82
|
+
@doc_trans zh_CN: "跳过前 `n` 个之后的元素。"
|
|
83
|
+
def drop(xs, n), do: ~python(<%= xs %>[<%= n %>:])
|
|
84
|
+
|
|
85
|
+
@doc "Pairs up two lists into `{a, b}` tuples, stopping at the shorter."
|
|
86
|
+
@doc_trans zh_CN: "将两个列表配成 `{a, b}` 元组,止于较短者。"
|
|
87
|
+
def zip(xs, ys), do: :builtins.list(:builtins.zip(xs, ys))
|
|
88
|
+
|
|
89
|
+
@doc "Each element paired with its index: `{element, index}`."
|
|
90
|
+
@doc_trans zh_CN: "每个元素与其下标配对:`{元素, 下标}`。"
|
|
91
|
+
@example """
|
|
92
|
+
gan> Enum.with_index([:a, :b])
|
|
93
|
+
[('a', 0), ('b', 1)]
|
|
94
|
+
"""
|
|
95
|
+
def with_index(xs), do: ~python([(x, i) for i, x in enumerate(<%= xs %>)])
|
|
96
|
+
|
|
97
|
+
@doc "Whether `x` is an element."
|
|
98
|
+
@doc_trans zh_CN: "`x` 是否为其中元素。"
|
|
99
|
+
def member?(xs, x), do: ~python(<%= x %> in <%= xs %>)
|
|
100
|
+
|
|
101
|
+
@doc "Whether `f` is truthy for every element."
|
|
102
|
+
@doc_trans zh_CN: "`f` 是否对所有元素为真值。"
|
|
103
|
+
def all?(xs, f), do: ~python(all(<%= f %>(x) for x in <%= xs %>))
|
|
104
|
+
|
|
105
|
+
@doc "Whether `f` is truthy for any element."
|
|
106
|
+
@doc_trans zh_CN: "`f` 是否对任一元素为真值。"
|
|
107
|
+
def any?(xs, f), do: ~python(any(<%= f %>(x) for x in <%= xs %>))
|
|
108
|
+
|
|
109
|
+
@doc "Whether the collection has no elements."
|
|
110
|
+
@doc_trans zh_CN: "集合是否为空。"
|
|
111
|
+
def empty?(xs), do: :builtins.len(xs) == 0
|
|
112
|
+
|
|
113
|
+
@doc "Removes duplicates, keeping first occurrences in order."
|
|
114
|
+
@doc_trans zh_CN: "去重,按序保留首次出现者。"
|
|
115
|
+
def uniq(xs), do: ~python(list(dict.fromkeys(<%= xs %>)))
|
|
116
|
+
|
|
117
|
+
@doc "Maps `f` (which returns a list) and concatenates the results."
|
|
118
|
+
@doc_trans zh_CN: "对每个元素应用返回列表的 `f`,并拼接全部结果。"
|
|
119
|
+
@example """
|
|
120
|
+
gan> Enum.flat_map([1, 2], fn x -> [x, x * 10] end)
|
|
121
|
+
[1, 10, 2, 20]
|
|
122
|
+
"""
|
|
123
|
+
def flat_map(xs, f), do: ~python([y for x in <%= xs %> for y in <%= f %>(x)])
|
|
124
|
+
|
|
125
|
+
@doc "Runs `f` on each element for its side effects; returns :ok."
|
|
126
|
+
@doc_trans zh_CN: "对每个元素执行 `f`(取其副作用);返回 :ok。"
|
|
127
|
+
def each(xs, f) do
|
|
128
|
+
~python([<%= f %>(x) for x in <%= xs %>])
|
|
129
|
+
:ok
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
@doc "The smallest element."
|
|
133
|
+
@doc_trans zh_CN: "最小元素。"
|
|
134
|
+
def min(xs), do: :builtins.min(xs)
|
|
135
|
+
|
|
136
|
+
@doc "The largest element."
|
|
137
|
+
@doc_trans zh_CN: "最大元素。"
|
|
138
|
+
def max(xs), do: :builtins.max(xs)
|
|
139
|
+
@doc "The first element for which `f` is truthy, or nil."
|
|
140
|
+
@doc_trans zh_CN: "首个使 `f` 为真值的元素,无则 nil。"
|
|
141
|
+
@example """
|
|
142
|
+
gan> Enum.find([1, 2, 3, 4], fn x -> x > 2 end)
|
|
143
|
+
3
|
|
144
|
+
"""
|
|
145
|
+
def find(xs, f), do: ~python(next((x for x in <%= xs %> if <%= f %>(x)), None))
|
|
146
|
+
|
|
147
|
+
@doc "The index of the first element for which `f` is truthy, or nil."
|
|
148
|
+
@doc_trans zh_CN: "首个使 `f` 为真值的元素下标,无则 nil。"
|
|
149
|
+
def find_index(xs, f),
|
|
150
|
+
do: ~python(next((i for i, x in enumerate(<%= xs %>) if <%= f %>(x)), None))
|
|
151
|
+
|
|
152
|
+
@doc "A map from each distinct element to its occurrence count."
|
|
153
|
+
@doc_trans zh_CN: "从每个不同元素到其出现次数的映射。"
|
|
154
|
+
@example """
|
|
155
|
+
gan> Enum.frequencies(["a", "b", "a"])
|
|
156
|
+
{'a': 2, 'b': 1}
|
|
157
|
+
"""
|
|
158
|
+
def frequencies(xs), do: :builtins.dict(:collections.Counter(xs))
|
|
159
|
+
|
|
160
|
+
@doc "Groups elements by the key computed by `f`, preserving order."
|
|
161
|
+
@doc_trans zh_CN: "按 `f` 计算的键分组,保持顺序。"
|
|
162
|
+
@example """
|
|
163
|
+
gan> Enum.group_by([1, 2, 3, 4, 5], fn x -> rem(x, 2) end)
|
|
164
|
+
{1: [1, 3, 5], 0: [2, 4]}
|
|
165
|
+
"""
|
|
166
|
+
def group_by(xs, f),
|
|
167
|
+
do: ~python({k: [x for x in <%= xs %> if <%= f %>(x) == k] for k in dict.fromkeys(<%= f %>(x) for x in <%= xs %>)})
|
|
168
|
+
|
|
169
|
+
@doc "The element maximizing the key computed by `f`; raises on empty."
|
|
170
|
+
@doc_trans zh_CN: "使 `f` 计算的键最大的元素;空集合抛错。"
|
|
171
|
+
def max_by(xs, f), do: :builtins.max(xs, key: f)
|
|
172
|
+
|
|
173
|
+
@doc "The element minimizing the key computed by `f`; raises on empty."
|
|
174
|
+
@doc_trans zh_CN: "使 `f` 计算的键最小的元素;空集合抛错。"
|
|
175
|
+
def min_by(xs, f), do: :builtins.min(xs, key: f)
|
|
176
|
+
|
|
177
|
+
@doc "The product of the elements (1 for an empty collection)."
|
|
178
|
+
@doc_trans zh_CN: "元素之积(空集合为 1)。"
|
|
179
|
+
def product(xs), do: :math.prod(xs)
|
|
180
|
+
|
|
181
|
+
@doc "Leading elements while `f` stays truthy."
|
|
182
|
+
@doc_trans zh_CN: "自头部起 `f` 持续为真值的元素。"
|
|
183
|
+
def take_while(xs, f), do: :builtins.list(:itertools.takewhile(f, xs))
|
|
184
|
+
|
|
185
|
+
@doc "Drops leading elements while `f` stays truthy, keeps the rest."
|
|
186
|
+
@doc_trans zh_CN: "丢弃头部 `f` 持续为真值的元素,保留其余。"
|
|
187
|
+
def drop_while(xs, f), do: :builtins.list(:itertools.dropwhile(f, xs))
|
|
188
|
+
|
|
189
|
+
@doc "Splits into chunks of `n` elements; the last chunk may be shorter."
|
|
190
|
+
@doc_trans zh_CN: "按每组 `n` 个元素分块;末组可较短。"
|
|
191
|
+
@example """
|
|
192
|
+
gan> Enum.chunk_every([1, 2, 3, 4, 5], 2)
|
|
193
|
+
[[1, 2], [3, 4], [5]]
|
|
194
|
+
"""
|
|
195
|
+
def chunk_every(xs, n),
|
|
196
|
+
do: ~python([<%= xs %>[i:i + <%= n %>] for i in range(0, len(<%= xs %>), <%= n %>)])
|
|
197
|
+
|
|
198
|
+
@doc "Concatenates a list of lists (one level)."
|
|
199
|
+
@doc_trans zh_CN: "拼接列表的列表(单层)。"
|
|
200
|
+
def concat(xss), do: ~python([y for x in <%= xss %> for y in x])
|
|
201
|
+
|
|
202
|
+
@doc "Puts `sep` between every two elements."
|
|
203
|
+
@doc_trans zh_CN: "在每两个元素之间放入 `sep`。"
|
|
204
|
+
@example """
|
|
205
|
+
gan> Enum.intersperse([1, 2, 3], :x)
|
|
206
|
+
[1, 'x', 2, 'x', 3]
|
|
207
|
+
"""
|
|
208
|
+
def intersperse(xs, sep), do: ~python([v for x in <%= xs %> for v in (x, <%= sep %>)][:-1])
|
|
209
|
+
|
|
210
|
+
@doc "`count` elements starting at `start` (negative start counts from the end)."
|
|
211
|
+
@doc_trans zh_CN: "自 `start` 起的 `count` 个元素(负的 start 从尾部数起)。"
|
|
212
|
+
def slice(xs, start, count), do: ~python(<%= xs %>[<%= start %>:] [:<%= count %>])
|
|
213
|
+
|
|
214
|
+
@doc "Collapses consecutive duplicate elements."
|
|
215
|
+
@doc_trans zh_CN: "折叠连续的重复元素。"
|
|
216
|
+
@example """
|
|
217
|
+
gan> Enum.dedup([1, 1, 2, 2, 2, 1])
|
|
218
|
+
[1, 2, 1]
|
|
219
|
+
"""
|
|
220
|
+
def dedup(xs),
|
|
221
|
+
do: ~python([x for i, x in enumerate(<%= xs %>) if i == 0 or x != <%= xs %>[i - 1]])
|
|
222
|
+
end
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
defmodule Keyword do
|
|
2
|
+
@moduledoc "Functions over keyword lists — lists of {atom, value} tuples (GEP-0010)."
|
|
3
|
+
@moduledoc_trans zh_CN: "关键字列表({原子, 值} 元组的列表)上的函数(GEP-0010)。"
|
|
4
|
+
|
|
5
|
+
@doc "The first value for `key`, or nil."
|
|
6
|
+
@doc_trans zh_CN: "键 `key` 的首个值,不存在时为 nil。"
|
|
7
|
+
@example """
|
|
8
|
+
gan> Keyword.get([a: 1, b: 2], :a)
|
|
9
|
+
1
|
|
10
|
+
"""
|
|
11
|
+
def get(kw, key), do: ~python(next((v for k, v in <%= kw %> if k == <%= key %>), None))
|
|
12
|
+
|
|
13
|
+
@doc "Replaces `key` with `value`, prepending it (Elixir Keyword.put)."
|
|
14
|
+
@doc_trans zh_CN: "以 `value` 替换 `key` 并将其前置(Elixir 的 Keyword.put)。"
|
|
15
|
+
def put(kw, key, value) do
|
|
16
|
+
[{key, value}] ++ Enum.reject(kw, fn {k, _} -> k == key end)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
@doc "The keys, in order, duplicates included."
|
|
20
|
+
@doc_trans zh_CN: "按序的全部键(含重复)。"
|
|
21
|
+
def keys(kw), do: Enum.map(kw, fn {k, _} -> k end)
|
|
22
|
+
|
|
23
|
+
@doc "The values, in order."
|
|
24
|
+
@doc_trans zh_CN: "按序的全部值。"
|
|
25
|
+
def values(kw), do: Enum.map(kw, fn {_, v} -> v end)
|
|
26
|
+
|
|
27
|
+
@doc "Whether `key` is present."
|
|
28
|
+
@doc_trans zh_CN: "是否存在键 `key`。"
|
|
29
|
+
def has_key?(kw, key), do: Enum.any?(kw, fn {k, _} -> k == key end)
|
|
30
|
+
@doc "Removes every entry for `key`."
|
|
31
|
+
@doc_trans zh_CN: "移除键为 `key` 的全部条目。"
|
|
32
|
+
def delete(kw, key), do: Enum.reject(kw, fn {k, _} -> k == key end)
|
|
33
|
+
|
|
34
|
+
@doc "Merges `kw2` into `kw1`; `kw2` wins, its entries appended."
|
|
35
|
+
@doc_trans zh_CN: "将 `kw2` 并入 `kw1`;`kw2` 胜出,其条目附加在后。"
|
|
36
|
+
@example """
|
|
37
|
+
gan> Keyword.merge([a: 1, b: 2], [b: 9, c: 3])
|
|
38
|
+
[('a', 1), ('b', 9), ('c', 3)]
|
|
39
|
+
"""
|
|
40
|
+
def merge(kw1, kw2) do
|
|
41
|
+
Enum.reject(kw1, fn {k, _} -> has_key?(kw2, k) end) ++ kw2
|
|
42
|
+
end
|
|
43
|
+
end
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
defmodule List do
|
|
2
|
+
@moduledoc "List-shape helpers; element-wise work lives in Enum (GEP-0010)."
|
|
3
|
+
@moduledoc_trans zh_CN: "列表形状辅助函数;逐元素操作在 Enum 中(GEP-0010)。"
|
|
4
|
+
|
|
5
|
+
@doc "The first element, or nil for an empty list."
|
|
6
|
+
@doc_trans zh_CN: "首元素,空列表为 nil。"
|
|
7
|
+
def first(xs), do: Enum.at(xs, 0)
|
|
8
|
+
|
|
9
|
+
@doc "The last element, or nil for an empty list."
|
|
10
|
+
@doc_trans zh_CN: "末元素,空列表为 nil。"
|
|
11
|
+
def last(xs), do: Enum.at(xs, -1)
|
|
12
|
+
|
|
13
|
+
@doc "Flattens nested lists to any depth."
|
|
14
|
+
@doc_trans zh_CN: "任意深度展平嵌套列表。"
|
|
15
|
+
@example """
|
|
16
|
+
gan> List.flatten([1, [2, [3, 4]], 5])
|
|
17
|
+
[1, 2, 3, 4, 5]
|
|
18
|
+
"""
|
|
19
|
+
def flatten(xs) do
|
|
20
|
+
Enum.flat_map(xs, fn x ->
|
|
21
|
+
if is_list(x) do
|
|
22
|
+
flatten(x)
|
|
23
|
+
else
|
|
24
|
+
[x]
|
|
25
|
+
end
|
|
26
|
+
end)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
@doc "Wraps a value in a list: nil becomes [], lists pass through, anything else becomes [value]."
|
|
30
|
+
@doc_trans zh_CN: "包装为列表:nil 变 [],列表原样返回,其余变 [值]。"
|
|
31
|
+
def wrap(value) do
|
|
32
|
+
cond do
|
|
33
|
+
is_nil(value) -> []
|
|
34
|
+
is_list(value) -> value
|
|
35
|
+
true -> [value]
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
@doc "A list of `n` copies of `value`."
|
|
40
|
+
@doc_trans zh_CN: "由 `n` 个 `value` 构成的列表。"
|
|
41
|
+
def duplicate(value, n), do: ~python([<%= value %>] * <%= n %>)
|
|
42
|
+
|
|
43
|
+
@doc "Inserts `value` at `index` (negative counts from the end, as in Elixir)."
|
|
44
|
+
@doc_trans zh_CN: "在 `index` 处插入 `value`(负数从尾部数起,同 Elixir)。"
|
|
45
|
+
def insert_at(xs, index, value),
|
|
46
|
+
do: ~python(<%= xs %>[:<%= index %>] + [<%= value %>] + <%= xs %>[<%= index %>:])
|
|
47
|
+
|
|
48
|
+
@doc "Removes the element at `index`; out-of-range leaves the list unchanged."
|
|
49
|
+
@doc_trans zh_CN: "删除 `index` 处的元素;越界时列表原样返回。"
|
|
50
|
+
def delete_at(xs, index),
|
|
51
|
+
do: ~python(<%= xs %>[:<%= index %>] + <%= xs %>[<%= index %>:][1:])
|
|
52
|
+
@doc "The list as a tuple."
|
|
53
|
+
@doc_trans zh_CN: "转换为元组的列表。"
|
|
54
|
+
def to_tuple(xs), do: :builtins.tuple(xs)
|
|
55
|
+
|
|
56
|
+
@doc "Whether the list starts with `prefix`."
|
|
57
|
+
@doc_trans zh_CN: "是否以 `prefix` 开头。"
|
|
58
|
+
def starts_with?(xs, prefix), do: ~python(<%= xs %>[:len(<%= prefix %>)] == <%= prefix %>)
|
|
59
|
+
|
|
60
|
+
@doc "Replaces the element at `index` (negative counts from the end)."
|
|
61
|
+
@doc_trans zh_CN: "替换 `index` 处的元素(负数从尾部数起)。"
|
|
62
|
+
def replace_at(xs, index, value),
|
|
63
|
+
do: ~python(<%= xs %>[:<%= index %>] + [<%= value %>] + <%= xs %>[<%= index %>:][1:])
|
|
64
|
+
|
|
65
|
+
@doc "Updates the element at `index` by `f`."
|
|
66
|
+
@doc_trans zh_CN: "以 `f` 更新 `index` 处的元素。"
|
|
67
|
+
@example """
|
|
68
|
+
gan> List.update_at([1, 2, 3], 1, fn v -> v * 10 end)
|
|
69
|
+
[1, 20, 3]
|
|
70
|
+
"""
|
|
71
|
+
def update_at(xs, index, f), do: replace_at(xs, index, f.(Enum.at(xs, index)))
|
|
72
|
+
end
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
defmodule Map do
|
|
2
|
+
@moduledoc "Data-first dict functions; all updates return new maps (GEP-0010)."
|
|
3
|
+
@moduledoc_trans zh_CN: "数据优先的 dict 函数;所有更新都返回新映射(GEP-0010)。"
|
|
4
|
+
|
|
5
|
+
@doc "The value for `key`, or `default` (nil unless given) when absent."
|
|
6
|
+
@doc_trans zh_CN: "键 `key` 的值;不存在时为 `default`(未给出则为 nil)。"
|
|
7
|
+
@example """
|
|
8
|
+
gan> Map.get(%{a: 1}, :b, 0)
|
|
9
|
+
0
|
|
10
|
+
"""
|
|
11
|
+
def get(m, key, default \\ nil), do: m.get(key, default)
|
|
12
|
+
|
|
13
|
+
@doc "A new map with `key` set to `value`."
|
|
14
|
+
@doc_trans zh_CN: "设置 `key` 为 `value` 后的新映射。"
|
|
15
|
+
@example """
|
|
16
|
+
gan> Map.put(%{a: 1}, :b, 2)
|
|
17
|
+
{'a': 1, 'b': 2}
|
|
18
|
+
"""
|
|
19
|
+
def put(m, key, value), do: ~python({**<%= m %>, <%= key %>: <%= value %>})
|
|
20
|
+
|
|
21
|
+
@doc "A new map without `key`."
|
|
22
|
+
@doc_trans zh_CN: "移除 `key` 后的新映射。"
|
|
23
|
+
def delete(m, key), do: ~python({k: v for k, v in <%= m %>.items() if k != <%= key %>})
|
|
24
|
+
|
|
25
|
+
@doc "The keys as a list."
|
|
26
|
+
@doc_trans zh_CN: "键的列表。"
|
|
27
|
+
def keys(m), do: :builtins.list(m.keys())
|
|
28
|
+
|
|
29
|
+
@doc "The values as a list."
|
|
30
|
+
@doc_trans zh_CN: "值的列表。"
|
|
31
|
+
def values(m), do: :builtins.list(m.values())
|
|
32
|
+
|
|
33
|
+
@doc "Merges `m2` into `m1`; `m2` wins on conflicts."
|
|
34
|
+
@doc_trans zh_CN: "将 `m2` 并入 `m1`;冲突时 `m2` 胜出。"
|
|
35
|
+
def merge(m1, m2), do: ~python({**<%= m1 %>, **<%= m2 %>})
|
|
36
|
+
|
|
37
|
+
@doc "Whether `key` is present."
|
|
38
|
+
@doc_trans zh_CN: "是否存在键 `key`。"
|
|
39
|
+
def has_key?(m, key), do: ~python(<%= key %> in <%= m %>)
|
|
40
|
+
|
|
41
|
+
@doc "The entries as a list of `{key, value}` tuples."
|
|
42
|
+
@doc_trans zh_CN: "以 `{键, 值}` 元组列表表示的条目。"
|
|
43
|
+
def to_list(m), do: :builtins.list(m.items())
|
|
44
|
+
|
|
45
|
+
@doc "An empty map."
|
|
46
|
+
@doc_trans zh_CN: "空映射。"
|
|
47
|
+
def new(), do: %{}
|
|
48
|
+
|
|
49
|
+
@doc "Updates `key` by `f`; uses `default` when the key is absent (Elixir Map.update/4)."
|
|
50
|
+
@doc_trans zh_CN: "以 `f` 更新 `key`;键不存在时使用 `default`(Elixir 的 Map.update/4)。"
|
|
51
|
+
@example """
|
|
52
|
+
gan> Map.update(%{a: 1}, :a, 0, fn v -> v + 10 end)
|
|
53
|
+
{'a': 11}
|
|
54
|
+
"""
|
|
55
|
+
def update(m, key, default, f) do
|
|
56
|
+
if has_key?(m, key) do
|
|
57
|
+
put(m, key, f.(get(m, key)))
|
|
58
|
+
else
|
|
59
|
+
put(m, key, default)
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
@doc "The value for `key`; raises Python KeyError when absent."
|
|
63
|
+
@doc_trans zh_CN: "键 `key` 的值;不存在时抛 Python KeyError。"
|
|
64
|
+
def fetch!(m, key), do: ~python(<%= m %>[<%= key %>])
|
|
65
|
+
|
|
66
|
+
@doc "Sets `key` only when absent."
|
|
67
|
+
@doc_trans zh_CN: "仅当 `key` 不存在时设置。"
|
|
68
|
+
def put_new(m, key, value) do
|
|
69
|
+
if has_key?(m, key) do
|
|
70
|
+
m
|
|
71
|
+
else
|
|
72
|
+
put(m, key, value)
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
@doc "The submap with only `keys` (missing keys ignored)."
|
|
77
|
+
@doc_trans zh_CN: "仅含 `keys` 的子映射(缺失的键忽略)。"
|
|
78
|
+
def take(m, keys), do: ~python({k: v for k, v in <%= m %>.items() if k in <%= keys %>})
|
|
79
|
+
|
|
80
|
+
@doc "The map without `keys`."
|
|
81
|
+
@doc_trans zh_CN: "移除 `keys` 后的映射。"
|
|
82
|
+
def drop(m, keys), do: ~python({k: v for k, v in <%= m %>.items() if k not in <%= keys %>})
|
|
83
|
+
|
|
84
|
+
@doc "Keeps entries for which `f` (receiving a `{key, value}` tuple) is truthy."
|
|
85
|
+
@doc_trans zh_CN: "保留使 `f`(接收 `{键, 值}` 元组)为真值的条目。"
|
|
86
|
+
@example """
|
|
87
|
+
gan> Map.filter(%{"a" => 1, "b" => 5}, fn pair -> elem(pair, 1) > 2 end)
|
|
88
|
+
{'b': 5}
|
|
89
|
+
"""
|
|
90
|
+
def filter(m, f), do: ~python({k: v for k, v in <%= m %>.items() if <%= f %>((k, v))})
|
|
91
|
+
end
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
defmodule String do
|
|
2
|
+
@moduledoc "Data-first string functions over Python str (GEP-0010)."
|
|
3
|
+
@moduledoc_trans zh_CN: "基于 Python str 的数据优先字符串函数(GEP-0010)。"
|
|
4
|
+
|
|
5
|
+
@doc "Uppercases the string."
|
|
6
|
+
@doc_trans zh_CN: "转为大写。"
|
|
7
|
+
def upcase(s), do: s.upper()
|
|
8
|
+
|
|
9
|
+
@doc "Lowercases the string."
|
|
10
|
+
@doc_trans zh_CN: "转为小写。"
|
|
11
|
+
def downcase(s), do: s.lower()
|
|
12
|
+
|
|
13
|
+
@doc "Uppercases the first character, lowercases the rest."
|
|
14
|
+
@doc_trans zh_CN: "首字符大写,其余小写。"
|
|
15
|
+
def capitalize(s), do: s.capitalize()
|
|
16
|
+
|
|
17
|
+
@doc "Splits on whitespace runs, dropping empty parts (Elixir semantics)."
|
|
18
|
+
@doc_trans zh_CN: "按连续空白切分并丢弃空段(Elixir 语义)。"
|
|
19
|
+
@example """
|
|
20
|
+
gan> String.split(" a b c ")
|
|
21
|
+
['a', 'b', 'c']
|
|
22
|
+
"""
|
|
23
|
+
def split(s), do: s.split()
|
|
24
|
+
|
|
25
|
+
@doc "Splits on the separator `sep`."
|
|
26
|
+
@doc_trans zh_CN: "按分隔符 `sep` 切分。"
|
|
27
|
+
def split_on(s, sep), do: s.split(sep)
|
|
28
|
+
|
|
29
|
+
@doc "Removes leading and trailing whitespace."
|
|
30
|
+
@doc_trans zh_CN: "去除首尾空白。"
|
|
31
|
+
def trim(s), do: s.strip()
|
|
32
|
+
|
|
33
|
+
@doc "Replaces every occurrence of `pattern` with `replacement`."
|
|
34
|
+
@doc_trans zh_CN: "将每处 `pattern` 替换为 `replacement`。"
|
|
35
|
+
def replace(s, pattern, replacement), do: s.replace(pattern, replacement)
|
|
36
|
+
|
|
37
|
+
@doc "Whether the string contains `part`."
|
|
38
|
+
@doc_trans zh_CN: "是否包含子串 `part`。"
|
|
39
|
+
def contains?(s, part), do: ~python(<%= part %> in <%= s %>)
|
|
40
|
+
|
|
41
|
+
@doc "Whether the string starts with `prefix`."
|
|
42
|
+
@doc_trans zh_CN: "是否以 `prefix` 开头。"
|
|
43
|
+
def starts_with?(s, prefix), do: s.startswith(prefix)
|
|
44
|
+
|
|
45
|
+
@doc "Whether the string ends with `suffix`."
|
|
46
|
+
@doc_trans zh_CN: "是否以 `suffix` 结尾。"
|
|
47
|
+
def ends_with?(s, suffix), do: s.endswith(suffix)
|
|
48
|
+
|
|
49
|
+
@doc "The number of characters (Unicode code points, Python `len`)."
|
|
50
|
+
@doc_trans zh_CN: "字符数(Unicode 码点,即 Python 的 `len`)。"
|
|
51
|
+
def length(s), do: :builtins.len(s)
|
|
52
|
+
|
|
53
|
+
@doc "The substring of `len` characters starting at `start` (negative start counts from the end)."
|
|
54
|
+
@doc_trans zh_CN: "自 `start` 起、长 `len` 的子串(负的 start 从尾部数起)。"
|
|
55
|
+
@example """
|
|
56
|
+
gan> String.slice("gandora", 3, 4)
|
|
57
|
+
'dora'
|
|
58
|
+
"""
|
|
59
|
+
def slice(s, start, len), do: ~python(<%= s %>[<%= start %>:] [:<%= len %>])
|
|
60
|
+
|
|
61
|
+
@doc "Pads on the left with spaces to `width`."
|
|
62
|
+
@doc_trans zh_CN: "左侧以空格填充至 `width`。"
|
|
63
|
+
def pad_leading(s, width), do: s.rjust(width)
|
|
64
|
+
|
|
65
|
+
@doc "Pads on the right with spaces to `width`."
|
|
66
|
+
@doc_trans zh_CN: "右侧以空格填充至 `width`。"
|
|
67
|
+
def pad_trailing(s, width), do: s.ljust(width)
|
|
68
|
+
|
|
69
|
+
@doc "Parses an integer; raises Python ValueError on bad input."
|
|
70
|
+
@doc_trans zh_CN: "解析整数;非法输入抛 Python ValueError。"
|
|
71
|
+
def to_integer(s), do: :builtins.int(s)
|
|
72
|
+
|
|
73
|
+
@doc "Parses a float; raises Python ValueError on bad input."
|
|
74
|
+
@doc_trans zh_CN: "解析浮点数;非法输入抛 Python ValueError。"
|
|
75
|
+
def to_float(s), do: :builtins.float(s)
|
|
76
|
+
@doc "The character at `index` (negative counts from the end), or nil."
|
|
77
|
+
@doc_trans zh_CN: "位于 `index` 的字符(负数从尾部数起),越界为 nil。"
|
|
78
|
+
def at(s, index) do
|
|
79
|
+
if index < :builtins.len(s) and index >= -:builtins.len(s) do
|
|
80
|
+
~python(<%= s %>[<%= index %>])
|
|
81
|
+
else
|
|
82
|
+
nil
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
@doc "The string reversed."
|
|
87
|
+
@doc_trans zh_CN: "反转后的字符串。"
|
|
88
|
+
def reverse(s), do: ~python(<%= s %>[::-1])
|
|
89
|
+
|
|
90
|
+
@doc "The string repeated `n` times."
|
|
91
|
+
@doc_trans zh_CN: "重复 `n` 次的字符串。"
|
|
92
|
+
def duplicate(s, n), do: ~python(<%= s %> * <%= n %>)
|
|
93
|
+
|
|
94
|
+
@doc "Removes leading whitespace."
|
|
95
|
+
@doc_trans zh_CN: "去除首部空白。"
|
|
96
|
+
def trim_leading(s), do: s.lstrip()
|
|
97
|
+
|
|
98
|
+
@doc "Removes trailing whitespace."
|
|
99
|
+
@doc_trans zh_CN: "去除尾部空白。"
|
|
100
|
+
def trim_trailing(s), do: s.rstrip()
|
|
101
|
+
|
|
102
|
+
@doc "The characters as a list of one-character strings."
|
|
103
|
+
@doc_trans zh_CN: "以单字符字符串列表表示的全部字符。"
|
|
104
|
+
@example """
|
|
105
|
+
gan> String.codepoints("héllo") |> Enum.take(2)
|
|
106
|
+
['h', 'é']
|
|
107
|
+
"""
|
|
108
|
+
def codepoints(s), do: :builtins.list(s)
|
|
109
|
+
|
|
110
|
+
@doc "Whether the compiled regex (`~r/.../`) matches anywhere in the string."
|
|
111
|
+
@doc_trans zh_CN: "编译后的正则(`~r/.../`)是否在字符串中命中。"
|
|
112
|
+
@example """
|
|
113
|
+
gan> String.match?("gandora-2026", ~r/\\d+/)
|
|
114
|
+
True
|
|
115
|
+
"""
|
|
116
|
+
def match?(s, regex), do: not is_nil(regex.search(s))
|
|
117
|
+
end
|