You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: Multiset/README.markdown
+27-16Lines changed: 27 additions & 16 deletions
Original file line number
Diff line number
Diff line change
@@ -2,20 +2,30 @@
2
2
3
3
A multiset (also known as a bag) is a data structure similar to a regular set, but it can store multiple instances of the same element.
4
4
5
-
The following all represent the same *set*, but do not represent the same *multiset*.
5
+
For example, if I added the elements 1, 2, 2 to a regular set, the set would only contain two items, since adding 2 a second time has no effect.
6
6
7
7
```
8
-
[1, 3, 2]
9
-
[1, 3, 2, 2]
8
+
var set = Set<Int>()
9
+
set.add(1) // set is now [1]
10
+
set.add(2) // set is now [1, 2]
11
+
set.add(2) // set is still [1, 2]
10
12
```
11
13
12
-
In this multiset implementation, ordering is unimportant. So these two multisets are identical:
14
+
By comparison, after adding the elements 1, 2, 2 to a multiset, it would contain three items.
13
15
14
16
```
15
-
[1, 2, 2]
16
-
[2, 1, 2]
17
+
var set = Multiset<Int>()
18
+
set.add(1) // set is now [1]
19
+
set.add(2) // set is now [1, 2]
20
+
set.add(2) // set is now [1, 2, 2]
17
21
```
18
22
23
+
You might be thinking that this looks an awful lot like an array. So why would you use a multiset? Let's consider the differences between the two…
24
+
25
+
- Ordering: arrays maintain the order of items added to them, multisets do not
26
+
- Testing for membership: testing whether an element is a member of the collection is O(N) for arrays, O(1) for multisets.
27
+
- Testing for subset: testing whether collection X is a subset of collection Y is a simple operation for a multiset, but complex for arrays
28
+
19
29
Typical operations on a multiset are:
20
30
21
31
- Add an element
@@ -24,6 +34,14 @@ Typical operations on a multiset are:
24
34
- Get the count for the whole set (the number of items that have been added)
25
35
- Check whether it is a subset of another multiset
26
36
37
+
One real-world use of multisets is to determine whether one string is a partial anagram of another. For example, the word "cacti" is a partial anagrams of "tactical". (In other words, I can rearrange the letters of "tactical" to make "cacti", with some letters left over.)
38
+
39
+
```swift
40
+
var cacti = Multiset<Character>("cacti")
41
+
var tactical = Multiset<Character>("tactical")
42
+
cacti.isSubSet(of: tactical) // true!
43
+
```
44
+
27
45
## Implementation
28
46
29
47
Under the hood, this implementation of Multiset uses a dictionary to store a mapping of elements to the number of times they've been added.
@@ -32,11 +50,7 @@ Here's the essence of it:
32
50
33
51
```swift
34
52
publicstructMultiset<Element: Hashable> {
35
-
fileprivatevar storage: [Element: UInt]
36
-
37
-
publicinit() {
38
-
storage = [:]
39
-
}
53
+
privatevar storage: [Element: UInt] = [:]
40
54
```
41
55
42
56
And here's how you'd use this classto create a multiset of strings:
@@ -49,11 +63,7 @@ Adding an element is a case of incrementing the counter for that element, or set
49
63
50
64
``` swift
51
65
public mutating func add (_ elem: Element) {
52
-
iflet currentCount = storage[elem] {
53
-
storage[elem] = currentCount +1;
54
-
} else {
55
-
storage[elem] =1
56
-
}
66
+
storage[elem, default: 0] +=1
57
67
}
58
68
```
59
69
@@ -62,6 +72,7 @@ Here's how you'd use this method to add to the set we created earlier:
62
72
```swift
63
73
set.add("foo")
64
74
set.add("foo")
75
+
set.allItems// returns ["foo", "foo"]
65
76
```
66
77
67
78
Our set now contains two elements, both the string "foo".
0 commit comments