If I got this array:
[0, 0, 1, 1, 1, 2, 3, 4, 5, 5]
How can I get:
[2, 3, 4]
This answer will hold the duplicate's value, but I want to remove that value as well.
If I got this array:
[0, 0, 1, 1, 1, 2, 3, 4, 5, 5]
How can I get:
[2, 3, 4]
This answer will hold the duplicate's value, but I want to remove that value as well.
Note that you need to import Foundation to use NSCountedSet. If you need a pure Swift solution to find the unique elements of a collection you can extend it constraining the elements to the Equatable protocol and check if you can not find the element index again checking if index(of: element) == nil using the index(after:) the element index as the startIndex of the collection subsequence:
Edit/update: Swift 4.2.1
Note that extending RangeReplacebleCollection it will cover StringProtocol types String
and Substring
as well:
Constraining the element to Equatable
Xcode 11 • Swift 5.1
extension RangeReplaceableCollection where Element: Equatable {
var uniqueElements: Self {
filter { self[index(after: firstIndex(of: $0)!)...].firstIndex(of: $0) == nil }
}
mutating func removeAllNonUniqueElements() { self = uniqueElements }
}
If you don't need to keep the collection original order, you can take advantage of the new Dictionary initializer but this would need constrain the elements to Hashable
:
init<S>(grouping values: S, by keyForValue: (S.Element) throws -> Dictionary<Key, Value>.Key) rethrows where Value == [S.Element], S : Sequence
and keep the keys where the values equals to 1
extension RangeReplaceableCollection where Element: Hashable {
var uniqueElementsSet: Set<Element> {
Set(Dictionary(grouping: self, by: { $0 }).compactMap{ $1.count == 1 ? $0 : nil })
}
}
Playground Testing
let numbers = [0, 0, 1, 1, 1, 2, 3, 4, 5, 5]
numbers.uniqueElements // [4, 2, 3]
If you need to keep the collection's order you can get the element frequency as shown in this answer and filter the unique elements:
extension Sequence where Element: Hashable {
var frequency: [Element: Int] { reduce(into: [:]) { $0[$1, default: 0] += 1 } }
}
extension RangeReplaceableCollection where Element: Hashable {
var uniqueElements: Self { filter { frequency[$0] == 1 } }
mutating func removeAllNonUniqueElements() { self = uniqueElements }
}
Playground testing
let numbers = [0, 0, 1, 1, 1, 2, 3, 4, 5, 5]
numbers.uniqueElements // [2, 3, 4]
var string = "0011123455"
string.uniqueElements // "234"
string.uniqueElementsSet // {"4", "3", "2"}
print(string) // "0011123455\n"
// mutating the string
string.removeAllNonUniqueElements()
print(string) // 234
If you want to filter only the numbers that appear 1 single time you can use the good old NSCountedSet
let nums = [0, 0, 1, 1, 1, 2, 3, 4, 5, 5]
let countedSet = NSCountedSet(array: nums)
let uniques = nums.filter { countedSet.count(for: $0) == 1 }
print(uniques) // [2, 3, 4]