Most common array elements

…衆ロ難τιáo~ 提交于 2019-11-28 12:35:49
Airspeed Velocity

edit: now with Swift 2.0 below

Not the most efficient of solutions but a simple one:

let a = [1,1,2,3,1,7,4,6,7,2]

var frequency: [Int:Int] = [:]

for x in a {
    // set frequency to the current count of this element + 1
    frequency[x] = (frequency[x] ?? 0) + 1
}

let descending = sorted(frequency) { $0.1 > $1.1 }

descending now consists of an array of pairs: the value and the frequency, sorted most frequent first. So the “top 5” would be the first 5 entries (assuming there were 5 or more distinct values). It shouldn't matter how big the source array is.

Here's a generic function version that would work on any sequence:

func frequencies
  <S: SequenceType where S.Generator.Element: Hashable>
  (source: S) -> [(S.Generator.Element,Int)] {

    var frequency: [S.Generator.Element:Int] = [:]

    for x in source {
        frequency[x] = (frequency[x] ?? 0) + 1
    }

    return sorted(frequency) { $0.1 > $1.1 }
}

frequencies(a)

For Swift 2.0, you can adapt the function to be a protocol extension:

extension SequenceType where Generator.Element: Hashable {
    func frequencies() -> [(Generator.Element,Int)] {

        var frequency: [Generator.Element:Int] = [:]

        for x in self {
            frequency[x] = (frequency[x] ?? 0) + 1
        }

        return frequency.sort { $0.1 > $1.1 }
    }
}

a.frequencies()

For Swift 3.0:

extension Sequence where Self.Iterator.Element: Hashable {
    func frequencies() -> [(Self.Iterator.Element,Int)] {

        var frequency: [Self.Iterator.Element:Int] = [:]

        for x in self {
            frequency[x] = (frequency[x] ?? 0) + 1
        }

        return frequency.sorted { $0.1 > $1.1 }
    }
}

For XCode 7.1 the solution is.

// Array of elements
let a = [7,3,2,1,4,6,8,9,5,3,0,7,2,7]

// Create a key for elements and their frequency
var times: [Int: Int] = [:]

// Iterate over the dictionary
for b in a {
    // Every time there is a repeat value add one to that key
    times[b] = (times[b] ?? 0) + 1
}

// This is for sorting the values
let decending = times.sort({$0.1 > $1.1})
// For sorting the keys the code would be 
// let decending = times.sort({$0.0 > $1.0})
// Do whatever you want with sorted array
print(decending)

Same as Airspeed Velocity, using a reduce instead of for-in:

extension Sequence where Self.Iterator.Element: Hashable {
    func frequencies() -> [(Self.Iterator.Element, Int)] {
        return reduce([:]) {
            var frequencies = $0
            frequencies[$1] = (frequencies[$1] ?? 0) + 1
            return frequencies
        }.sorted { $0.1 > $1.1 }
    }
}

But please note that, here, using reduce with a struct is not as efficient as a for-in because of the struct copy cost. So you will generally prefer the for-in way of doing it.

[edit: gosh, the article is by the same guy as the top answer!]

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!