Structures
The following structures are available globally.
-
A
Multiset
is an unordered collection of hashable elements.The Multiset collection has similarities with Set and Dictionary, two collections in the swift standard library The key difference from a set is that a Multiset can have repeated Elements. It does this by storing a dictionary (called ‘content’) of type [Element, Int].
Initialisation
A Multiset can be created by an array literal of type [Element] as in:
let ingredients: Multiset = ["coffee", "milk", "sugar", "sugar"]
or using variadic initialiser for two or more elements:
let fruit = Multiset("Apple", "Orange", "Apple") // ["Apple":2, "Orange":1] // But can't do Multiset("Apple") because "Apple" is seen as an array of Characters!)
or using a dictionary literal of type [Element:Int] as in:
let truth: Multiset = [true:3, false:2]
or from a sequence (which may include repeated elements):
let numbers: Multiset = [1000, 2000, 3000, 1000] // [1000:2, 2000:1, 3000:1]
for an empty multiset you must specify the Generic Parameter:
let words: Multiset<String> = [] let numbers = Multiset<Int>()
Inserting and Removing Elements
To insert elements:
var multi = Multiset<String>() // [] multi.insert("Small") // ["Small":1] multi.insert("Small") // ["Small":2] multi.insert("Big", count: 6) // ["Small":2, "Big"]
To remove elements:
var multi: Multiset = [1000:1, 2000:1, 3000:10] multi.remove(1000) // [2000:1, 3000:10] multi.remove(3000, count: 3) // [2000:1, 3000:7] multi.remove(3000, count: 3) // [2000:1, 3000:7]
If there aren’t enough elements then remove will not remove any of them and this is indicated by the function returning false:
var multi: Multiset = [2000:1, 3000:7] let resulta = multi.remove(7777) // resulta is false let resultb = multi.remove(3000, count: 10) // resultb is false
Or to remove as many as are available then use the isPossible override:
var multi: Multiset = [2000:1, 3000:7] let resulta = multi.remove(ifPossible: 3000, count: 100) // resulta is 7 and multi is [2000:1] let resultb = multi.remove(ifPossible: 3000:100) // resultb is false
To remove all of certain elements:
var multi: Multiset = ["AAA":3, "BBB":4, "CCC":4] multi.removeAll("AAA") // ["BBB":4, "CCC":4] multi.removeAll() // []
To just set the number of a certain type of element:
var truth: Multiset = [true:3, false:4] truth.update(count: 5, for: true) // [true:5, false:4] truth.update(count: 0, for: false) // [true:5] truth.update(count: 7, for: false) // [true:5, false:7]
Iterating
There are 3 ways to iterate through a multiset:
1) To iterate through all the elements of a multiset:
for size in Multiset(["Big":3, "Small":2]) { print(size) } Note that elements of the same type will come grouped together but the order of different groups is not defined so: either prints "Big" "Big" "Big" "Small" "Small" or prints "Small" "Small" "Big" "Big" "Big"
2) To iterate through groups of different types of elements use
grouped()
for (element, count) in Multiset(["Big":3, "Small":2]).grouped() { print(element, count) } Note that the order of the elements is not defined so: either prints ("Big",3) and then ("Small":2) or prints ("Small":2) and then ("Big",3)
3) To iterate through just the distinct elements of a multiset use
distinct()
:for size in Multiset(["Big":3, "Small":2]).distinct() { print(size) } Note that the order of the elements is not defined so: either prints "Big" and then "Small" or prints "Small" and then "Big"
Sequence and Collection Operations
In addition to the
Multiset
type’s multiset operations, you can use any nonmutating sequence or collection methods with a multiset.let factorsOf12: Multiset = [2:2, 3:1] if factorsOf12.isEmpty { print("No factors") } else { print("Twelve has \(factorsOf12.count) factors.") print("Twelve has \(factorsOf12.distinctCount) distinct factors.") } // Prints "Twelve has 3 factors." // Prints "Twelve has 2 distinct factors." let factorsProduct = factors.reduce(1, *) // 'factorsProduct' == 12 let factorsStrings = factors.sorted().map(String.init) // 'primeStrings' == ["2", "2", "3"]
And as a collection you can use index operations:
var multi: Multiset = ["AA":3, "BB":3] if let index = multi.firstIndex(of: "BB") { multi.remove(at: index) // ["AA":3, "BB":2] }
Set Algebra Operations
Multiset provides the Set Algebra operations which are the same as the ones used by Set. You can test a multiset for membership of an element or check its intersection with other multisets:
contains(_:)
tests whether a multiset contains a specific element.equal to
operator (==
) tests whether two multisets contain the same elements and the sanem number of those elements.isSubset(of:)
tests whether another multiset contains at least as many of each of the current multisets elements.isSuperset(of:)
tests whether a multiset contains at least as many of each of another multisets elements.isStrictSubset(of:)
andisStrictSuperset(of:)
test whether a multiset is a subset or superset of, but not equal to, another multiset.isDisjoint(with:)
tests whether a multiset has any elements in common with another multiset.Note
Note that when multisets have more than one of the same element some of these operations may not be as obvious as with sets. For example even though: AAB = Multiset([
A
:2,B
:1]) and ABB = Multiset([A
:2,B
:1]) both containsA
andB
and no other elements, neither contains the other.You can also combine, exclude, or subtract the elements of two multisets:
union(_:)
creates a new multiset with the elements of a multiset and another multiset or sequence.intersection(_:)
creates a new multiset with only the elements common to a multiset and another multiset or sequence.symmetricDifference(_:)
creates a new multiset with the elements that are in either a multiset or another multiset or sequence, but not in both.subtracting(_:)
creates a new multiset with the elements of a multiset that are not also in another multiset or sequence.Note
Note that when multisets have more than one of the same element some of these operations may not be as obvious as with sets. For example if: AAB = Multiset([
A
:2,B
:1]) and ABC = Multiset([A
:1,B
:1,C
:1]) then AAB.symmetricDifference(ABC) is Multiset([A
:1,C
:1])You can modify a multiset in place by using these mutating methods:
formUnion(_:)
,formIntersection(_:)
,formSymmetricDifference(_:)
, andsubtract(_:)
.Multiset operations are not limited to use with other multisets. You can perform many operations with sets, arrays or any sequence with the same Element type:
let word = Multiset(Array("SINS")) word is now ["S":2, "I":1, "N":1] although Multisets are not ordered so may be a different order. let scrabbleHand: [Character] = ["MISSING"] // Tests whether the characters of the word SINS can be found in the // array of characters MISSING: print(word.isSubset(of: scrabbleHand) ) // Prints "true" // Performs an intersection with an Array<Int> let primes: Multiset = [2, 3, 5, 7, 11, 13, 17, 19, 23] let favoriteNumbers = [5, 7, 15, 21] print(primes.intersection(favoriteNumbers)) // Prints "[5, 7]"
Other reading
Because Multiset has some similarity with both Set and Dictionary, reading the documentation or source for those may also be useful:
https://github.com/apple/swift/blob/master/stdlib/public/core/Set.swift https://github.com/apple/swift/blob/master/stdlib/public/core/Dictionary.swift
See moreDeclaration
Swift
public struct Multiset<Element> where Element : Hashable
-
Declaration
Swift
public struct MultisetIndex<Element> where Element : Hashable