Reputation: 2642
I am substracting two Array of Integers. I did the substraction using sets :
let numbersA = [1, 2, 3]
let numbersB = [3, 4, 5]
Set(numbersA).subtracting(numbersB)
but I then realized that I have multiplicity in my arrays, and I should take it into account. What is the data structure for multisets in Swift?
Upvotes: 0
Views: 1500
Reputation: 2257
As you say, swift does not have Multiset as a native type. I implemented a fairly thorough implementation of Multiset in Swift here:
https://github.com/Cortado-J/Multiset
and full documentation of that library with usage examples here:
https://cortado-j.github.io/Multiset/Structs/Multiset.html
Upvotes: 0
Reputation: 2642
In swift 5, there is no Multiset implementation in the core library.
You can reproduce the Multiset behavior by using a dictionary [Element:Multiplicity]
.
Your code will be:
let numbersA = [1, 2, 3, 3]
let numbersB = [3, 4, 5]
Set(numbersA).subtracting(numbersB) // [1, 2, 3]
As pointed out by Leo Dabus in comment, this gives you an unordered collection as a result.
You can find a good tutorial on multisets at https://github.com/raywenderlich/swift-algorithm-club/tree/master/Multiset
Here is a ready to use implementation of multiset. I added to it the substracting implementation. Notice it can be considered an incomplet implementation of a Multiset since, for exemple, it doesn't extends the Collection protocol.
//
// Multiset.swift
// Multiset
//
// Created by Simon Whitaker on 28/08/2017.
//
// Extended by Jeremy Cochoy on 17/11/2019
import Foundation
public struct Multiset<T: Hashable> {
private var storage: [T: UInt] = [:]
public private(set) var count: UInt = 0
public init() {}
public init<C: Collection>(_ collection: C) where C.Element == T {
for element in collection {
self.add(element)
}
}
public mutating func add (_ elem: T) {
storage[elem, default: 0] += 1
count += 1
}
public mutating func remove (_ elem: T) {
if let currentCount = storage[elem] {
if currentCount > 1 {
storage[elem] = currentCount - 1
} else {
storage.removeValue(forKey: elem)
}
count -= 1
}
}
public func isSubSet (of superset: Multiset<T>) -> Bool {
for (key, count) in storage {
let supersetcount = superset.storage[key] ?? 0
if count > supersetcount {
return false
}
}
return true
}
public func count(for key: T) -> UInt {
return storage[key] ?? 0
}
public var allItems: [T] {
var result = [T]()
for (key, count) in storage {
for _ in 0 ..< count {
result.append(key)
}
}
return result
}
public func subtracting(_ elems: [T]) -> Multiset<T> {
var resultSet = self
elems.forEach { resultSet.remove($0) }
return resultSet
}
}
// MARK: - Equatable
extension Multiset: Equatable {
public static func == (lhs: Multiset<T>, rhs: Multiset<T>) -> Bool {
if lhs.storage.count != rhs.storage.count {
return false
}
for (lkey, lcount) in lhs.storage {
let rcount = rhs.storage[lkey] ?? 0
if lcount != rcount {
return false
}
}
return true
}
}
// MARK: - ExpressibleByArrayLiteral
extension Multiset: ExpressibleByArrayLiteral {
public init(arrayLiteral elements: T...) {
self.init(elements)
}
}
Upvotes: 1