Elixir MapSet与Range #
一、MapSet基础 #
1.1 MapSet定义 #
MapSet是无序、唯一元素的集合:
elixir
iex(1)> MapSet.new([1, 2, 3, 4, 5])
MapSet.new([1, 2, 3, 4, 5])
iex(2)> MapSet.new([1, 2, 2, 3, 3, 3])
MapSet.new([1, 2, 3])
iex(3)> MapSet.new()
MapSet.new([])
1.2 特性 #
- 元素唯一
- 无序存储
- 快速成员检查
- 元素可以是任意类型
elixir
iex(1)> set = MapSet.new([1, 2, 3])
MapSet.new([1, 2, 3])
iex(2)> MapSet.size(set)
3
iex(3)> MapSet.member?(set, 2)
true
iex(4)> MapSet.member?(set, 5)
false
二、MapSet操作 #
2.1 添加元素 #
elixir
iex(1)> set = MapSet.new([1, 2, 3])
MapSet.new([1, 2, 3])
iex(2)> MapSet.put(set, 4)
MapSet.new([1, 2, 3, 4])
iex(3)> MapSet.put(set, 2)
MapSet.new([1, 2, 3])
2.2 删除元素 #
elixir
iex(1)> set = MapSet.new([1, 2, 3])
MapSet.new([1, 2, 3])
iex(2)> MapSet.delete(set, 2)
MapSet.new([1, 3])
2.3 成员检查 #
elixir
iex(1)> set = MapSet.new([1, 2, 3])
MapSet.new([1, 2, 3])
iex(2)> MapSet.member?(set, 2)
true
iex(3)> MapSet.member?(set, 5)
false
iex(4)> 2 in set
true
2.4 集合运算 #
并集 #
elixir
iex(1)> a = MapSet.new([1, 2, 3])
MapSet.new([1, 2, 3])
iex(2)> b = MapSet.new([3, 4, 5])
MapSet.new([3, 4, 5])
iex(3)> MapSet.union(a, b)
MapSet.new([1, 2, 3, 4, 5])
交集 #
elixir
iex(1)> MapSet.intersection(a, b)
MapSet.new([3])
差集 #
elixir
iex(1)> MapSet.difference(a, b)
MapSet.new([1, 2])
iex(2)> MapSet.difference(b, a)
MapSet.new([4, 5])
对称差集 #
elixir
iex(1)> MapSet.symmetric_difference(a, b)
MapSet.new([1, 2, 4, 5])
2.5 子集判断 #
elixir
iex(1)> a = MapSet.new([1, 2])
MapSet.new([1, 2])
iex(2)> b = MapSet.new([1, 2, 3])
MapSet.new([1, 2, 3])
iex(3)> MapSet.subset?(a, b)
true
iex(4)> MapSet.subset?(b, a)
false
iex(5)> MapSet.equal?(a, b)
false
2.6 相等判断 #
elixir
iex(1)> a = MapSet.new([1, 2, 3])
MapSet.new([1, 2, 3])
iex(2)> b = MapSet.new([3, 2, 1])
MapSet.new([1, 2, 3])
iex(3)> MapSet.equal?(a, b)
true
2.7 转换 #
elixir
iex(1)> set = MapSet.new([1, 2, 3])
MapSet.new([1, 2, 3])
iex(2)> MapSet.to_list(set)
[1, 2, 3]
iex(3)> Enum.to_list(set)
[1, 2, 3]
三、MapSet遍历 #
3.1 使用Enum #
elixir
iex(1)> set = MapSet.new([1, 2, 3, 4, 5])
MapSet.new([1, 2, 3, 4, 5])
iex(2)> Enum.map(set, fn x -> x * 2 end)
[2, 4, 6, 8, 10]
iex(3)> Enum.filter(set, fn x -> x > 2 end)
[3, 4, 5]
iex(4)> Enum.reduce(set, 0, fn x, acc -> acc + x end)
15
3.2 使用推导式 #
elixir
iex(1)> set = MapSet.new([1, 2, 3, 4, 5])
MapSet.new([1, 2, 3, 4, 5])
iex(2)> for x <- set, x > 2, do: x * 2
[6, 8, 10]
四、MapSet使用场景 #
4.1 去重 #
elixir
iex(1)> list = [1, 2, 2, 3, 3, 3, 4, 4, 4, 4]
[1, 2, 2, 3, 3, 3, 4, 4, 4, 4]
iex(2)> list |> MapSet.new() |> MapSet.to_list()
[1, 2, 3, 4]
iex(3)> Enum.uniq(list)
[1, 2, 3, 4]
4.2 成员检查 #
elixir
defmodule AccessControl do
@admin_roles MapSet.new(["super_admin", "admin", "moderator"])
def admin?(role) do
MapSet.member?(@admin_roles, role)
end
end
4.3 标签系统 #
elixir
defmodule TagSystem do
def add_tags(post, new_tags) do
current_tags = MapSet.new(post.tags)
new_tags_set = MapSet.new(new_tags)
updated_tags = MapSet.union(current_tags, new_tags_set)
%{post | tags: MapSet.to_list(updated_tags)}
end
def remove_tags(post, tags_to_remove) do
current_tags = MapSet.new(post.tags)
remove_set = MapSet.new(tags_to_remove)
updated_tags = MapSet.difference(current_tags, remove_set)
%{post | tags: MapSet.to_list(updated_tags)}
end
def common_tags(post1, post2) do
tags1 = MapSet.new(post1.tags)
tags2 = MapSet.new(post2.tags)
MapSet.intersection(tags1, tags2)
|> MapSet.to_list()
end
end
五、Range基础 #
5.1 Range定义 #
Range表示一个范围的整数:
elixir
iex(1)> 1..5
1..5
iex(2)> 1..10//2
1..10//2
iex(3)> 10..1
10..1
5.2 特性 #
- 包含起始和结束值
- 可以递增或递减
- 支持步长
elixir
iex(1)> range = 1..5
1..5
iex(2)> Enum.to_list(range)
[1, 2, 3, 4, 5]
iex(3)> Enum.to_list(5..1)
[5, 4, 3, 2, 1]
iex(4)> Enum.to_list(1..10//2)
[1, 3, 5, 7, 9]
5.3 成员检查 #
elixir
iex(1)> 3 in 1..5
true
iex(2)> 6 in 1..5
false
iex(3)> 5 in 1..5
true
六、Range操作 #
6.1 遍历 #
elixir
iex(1)> Enum.map(1..5, fn x -> x * 2 end)
[2, 4, 6, 8, 10]
iex(2)> Enum.each(1..3, fn x -> IO.puts(x) end)
1
2
3
:ok
6.2 范围信息 #
elixir
iex(1)> range = 1..10
1..10
iex(2)> Range.size(range)
10
iex(3)> Range.new(1, 5)
1..5
iex(4)> Range.disjoint?(1..5, 6..10)
true
iex(5)> Range.disjoint?(1..5, 5..10)
false
6.3 步长范围 #
elixir
iex(1)> 1..10//2
1..10//2
iex(2)> Enum.to_list(1..10//2)
[1, 3, 5, 7, 9]
iex(3)> Enum.to_list(10..1//-1)
[10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
iex(4)> Enum.to_list(1..10//3)
[1, 4, 7, 10]
6.4 转换 #
elixir
iex(1)> Enum.to_list(1..5)
[1, 2, 3, 4, 5]
iex(2)> Enum.into(1..3, [])
[1, 2, 3]
七、Range模式匹配 #
7.1 匹配范围 #
elixir
iex(1)> first..last = 1..10
1..10
iex(2)> first
1
iex(3)> last
10
iex(4)> first..last//step = 1..10//2
1..10//2
iex(5)> step
2
7.2 在case中使用 #
elixir
iex(1)> case 5 do
...> n when n in 1..10 -> "small"
...> n when n in 11..100 -> "medium"
...> _ -> "large"
...> end
"small"
八、Range使用场景 #
8.1 循环替代 #
elixir
for i <- 1..10 do
IO.puts(i)
end
8.2 分页 #
elixir
defmodule Pagination do
def page_range(current, total, window \\ 2) do
start = max(1, current - window)
finish = min(total, current + window)
start..finish
end
end
Pagination.page_range(5, 10)
8.3 字符范围 #
elixir
iex(1)> ?a..?z
97..122
iex(2)> for code <- ?a..?z, do: <<code>>
["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p",
"q", "r", "s", "t", "u", "v", "w", "x", "y", "z"]
8.4 日期范围 #
elixir
defmodule DateRange do
def days_in_range(start_date, end_date) do
Date.diff(end_date, start_date) + 1
end
def date_range(start_date, end_date) do
days = Date.diff(end_date, start_date)
for offset <- 0..days do
Date.add(start_date, offset)
end
end
end
九、性能考虑 #
9.1 MapSet vs List #
| 操作 | MapSet | List |
|---|---|---|
| 成员检查 | O(log n) | O(n) |
| 添加 | O(log n) | O(1) 头部 |
| 删除 | O(log n) | O(n) |
9.2 Range vs List #
Range是惰性的,不会立即生成所有元素:
elixir
iex(1)> 1..1_000_000
1..1000000
iex(2)> Enum.to_list(1..1_000_000)
十、总结 #
MapSet #
| 操作 | 示例 |
|---|---|
| 创建 | MapSet.new([1, 2, 3]) |
| 添加 | MapSet.put(set, 4) |
| 删除 | MapSet.delete(set, 2) |
| 成员检查 | MapSet.member?(set, 2) |
| 并集 | MapSet.union(a, b) |
| 交集 | MapSet.intersection(a, b) |
Range #
| 操作 | 示例 |
|---|---|
| 创建 | 1..10 |
| 步长 | 1..10//2 |
| 成员检查 | 5 in 1..10 |
| 大小 | Range.size(1..10) |
| 遍历 | Enum.map(1..5, fn x -> x end) |
准备好学习控制流了吗?让我们进入下一章。
最后更新:2026-03-27