轨道
/
Elm
Elm
/
练习
/
把它们全都抓到手
把它们全都抓到手

把它们全都抓到手

学习练习

简介

Set

Set a是类型为a的唯一值序列。这些值必须属于comparable类型(Int、Float、Time、Char、String,以及由可比较类型组成的元组或数组)。

你可以用Set.toList和Set.fromList在数组和集合之间互相转换。由于Set的内部结构,从Set.fromList得到的数组保证是有序的。

Set.fromList [2, 3, 3, 3, 1, 1, 2]
    --> Set.fromList [1, 2, 3]

Set.toList (Set.fromList [2, 3, 3, 3, 1, 1, 2])
    --> [1, 2, 3]

你可以用Set.empty、Set.singleton、Set.insert和Set.remove来创建和填充集合。

Set.empty
    --> Set.fromList []

Set.singleton "hi"
    --> Set.fromList ["hi"]

eightyEight = Set.singleton 88

Set.insert 88 eightyEight
    --> Set.fromList [88]

Set.insert 89 eightyEight
    --> Set.fromList [88, 89]

Set.remove 88 eightyEight
    --> Set.fromList []

Set.remove 89 eightyEight
    --> Set.fromList [88]

你可以用Set.member、Set.isEmpty和Set.size这几个函数查询集合的内容。

Set.member 88 eightyEight
    --> True

Set.isEmpty eightyEight
    --> False

Set.size eightyEight
    --> 1

集合还可以用Set.union、Set.intersect和Set.diff组合起来。

a = Set.fromList [1, 10, 100]
b = Set.fromList [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

Set.union a b
    --> Set.fromList [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 100]

Set.intersect a b
    --> Set.fromList [1, 10]

Set.diff a b
    --> Set.fromList [100]

Set.diff b a
    --> Set.fromList [2, 3, 4, 5, 6, 7, 8, 9]

你可以对集合进行过滤和划分。

even n = modBy 2 n == 0

Set.filter even b
    --> Set.fromList [2, 4, 6, 8, 10]

Set.partition even b
    --> (Set.fromList [2, 4, 6, 8, 10], Set.fromList [1, 3, 5, 7, 9])

说明

你对 Blorkemon™️ 卡牌的怀旧之情丝毫没有减退,你甚至又开始收集它们,还拉着朋友们一起加入。

在本练习中,Card收藏由Set Card表示,因为当你的目标是集齐所有现有卡牌时,重复的卡牌并不重要。

1. 开始收藏

你非常希望朋友们加入你的 Blorkemon™️ 狂热,最好的办法就是送他们一张卡牌,帮他们开启收藏。

实现newCollection,它把一张卡牌转换成一个收藏。

newCollection "Newthree"
    --> Set.fromList ["Newthree"]

2. 扩充收藏

一旦你有了收藏,它就会有自己的生命,必须不断壮大。

实现addCard,它接收一个Card和一个收藏,并返回一个Tuple,其中包含两个值:一个Bool,表示该Card是否已经在收藏中;以及添加了该卡牌后的收藏。

addCard "Scientuna" (Set.fromList ["Newthree"])
    --> (False, Set.fromList ["Newthree", "Scientuna"])

3. 开始交易

既然你的朋友们又为 Blorkemon™️ 疯狂了,你就可以借此通过交换卡牌来扩充自己的收藏。

并不是每一笔交易都值得做,或者根本没法做。

你不能交换一张自己没有的卡牌,也不应该用一张卡牌去换一张你已经有的卡牌。

实现tradeCard,它接收两张要交换的卡牌(你的和对方的)以及你当前的收藏。

返回值是一个包含两个值的Tuple:一个Bool,说明这笔交易是否可行且值得做;以及如果你做了这笔交易最终会得到的收藏(即使实际上并不可行)。

tradeCard "Scientuna" "Newthree" (Set.fromList ["Scientuna"])
    --> (True, Set.fromList ["Newthree"])

4. 每种卡牌只能有一张

你在跳蚤市场发现了一批旧卡牌。

你必须对卡牌排序并去除重复项,以便把这个列表和你的收藏进行比较。

实现removeDuplicates,它会对一个卡牌列表排序,并返回一个排序后、去重后的卡牌列表。

removeDuplicates ["Newthree", "Newthree", "Newthree", "Scientuna"]
    --> ["Newthree", "Scientuna"]

5. 他们没有的卡牌

是时候为你的收藏感到高兴了。

实现extraCards,它接收你的收藏和另一个收藏,并返回另一个收藏没有的卡牌数量。

extraCards (Set.fromList ["Scientuna"]) (Set.fromList ["Newthree", "Scientuna"])
    --> 0

6. 他们都有的卡牌

你和热衷 Blorkemon™️ 的朋友们聚在一起,想知道哪些卡牌最常见。

实现boringCards,它接收一个收藏列表,并返回一个排序后的卡牌列表,这些卡牌是所有收藏都有的。

boringCards [Set.fromList ["Scientuna"], Set.fromList ["Newthree", "Scientuna"]]
    --> ["Scientuna"]

7. 所有卡牌

你和朋友们加起来是否拥有所有的 Blorkemon™️ 卡牌?

实现totalCards,它接收一个收藏列表,并返回所有收藏中不同卡牌的总数。

totalCards [Set.fromList ["Scientuna"], Set.fromList ["Newthree", "Scientuna"]]
    --> 2

8. 闪亮制胜

你的侄子很快要来看你,你想给他留下深刻印象。

小孩子都喜欢闪亮的东西,对吧?

Blorkemon™️ 卡牌也可以是闪亮的!

实现splitShinyCards,它接收一个收藏,并返回一个Tuple,其中包含两个排序后的卡牌列表:一个列表包含所有以"Shiny"开头的卡牌,另一个列表包含其余卡牌。

splitShinyCards (Set.fromList ["Newthree", "Scientuna", "Shiny Scientuna"])
    --> (["Shiny Scientuna"], ["Newthree", "Scientuna"])
通过 GitHub 编辑 链接将在新窗口或新标签页中打开
Elm Exercism

准备好开始 把它们全都抓到手 了吗?

注册 Exercism,借助 28 个概念110 个练习 和真人导师指导,学习并掌握 Elm,全部免费。