Swift 4 - How to return a count of duplicate value

2020-03-30 06:18发布

问题:

I have an array with multiple values (Doubles), many of which are duplicates. I'd like to return or print a list of all unique values, along with a count of how many times a given value appears in the array. I'm pretty new to Swift and I've tried a couple of different things but I'm unsure of the best way to accomplish this.

Something like this: [65.0, 65.0, 65.0, 55.5, 55.5, 30.25, 30.25, 27.5]

Would print (for example): "3 at 65.0, 2 at 55.5, 2 at 30.25, 1 at 27.5."

I'm not really concerned about the output as much as the method to accomplish this.

Thanks!

回答1:

You can enumerate through the array and add the values to the dictionary.

var array: [CGFloat] =  [65.0, 65.0, 65.0, 55.5, 55.5, 30.25, 30.25, 27.5]
var dictionary = [CGFloat: Int]()

for item in array {
   dictionary[item] = dictionary[item] ?? 0 + 1
}

print(dictionary)

or you can do foreach on array:

array.forEach { (item) in
  dictionary[item] = dictionary[item] ?? 0 + 1
}

print(dictionary)

or as @rmaddy said:

var set: NSCountedSet =  [65.0, 65.0, 65.0, 55.5, 55.5, 30.25, 30.25, 27.5]
var dictionary = [Float: Int]()
set.forEach { (item) in
  dictionary[item as! Float] = set.count(for: item)
}

print(dictionary)


回答2:

As @rmaddy already commented you can use Foundation NSCountedSet as follow:

import Foundation // or iOS UIKit or macOS Cocoa

let values = [65.0, 65.0, 65.0, 55.5, 55.5, 30.25, 30.25, 27.5]
let countedSet = NSCountedSet(array: values)
print(countedSet.count(for: 65.0))   // 3
for value in countedSet {
    print("Element:", value, "count:", countedSet.count(for: value))
}

Xcode 11 • Swift 5.1

You can also extend NSCountedSet to return an array of tuples or a dictionary:

extension NSCountedSet {
    var occurences: [(object: Any, count: Int)] { map { ($0, count(for: $0))} }
    var dictionary: [AnyHashable: Int] {
        reduce(into: [:]) {
            guard let key = $1 as? AnyHashable else { return }
            $0[key] = count(for: key)
        }
    }
}

let values = [65.0, 65.0, 65.0, 55.5, 55.5, 30.25, 30.25, 27.5]
let countedSet = NSCountedSet(array: values)
for (key, value) in countedSet.dictionary {
    print("Element:", key, "count:", value)
}

For a Swift native solution we can extend Sequence constraining its elements to Hashable:

extension Sequence where Element: Hashable {
    var frequency: [Element: Int] { reduce(into: [:]) { $0[$1, default: 0] += 1 } }
}

let values = [65.0, 65.0, 65.0, 55.5, 55.5, 30.25, 30.25, 27.5]
let frequency = values.frequency
frequency[65] // 3
for (key, value) in frequency {
    print("Element:", key, "count:", value)
}

Those will print

Element: 27.5 count: 1
Element: 30.25 count: 2
Element: 55.5 count: 2
Element: 65 count: 3