计算数组中的数字并按顺序在swift中对它们进行排序

时间:2016-01-05 15:02:28

标签: arrays swift

有没有一种简单的方法可以按数字对数组进行排序?如果一个数字具有相同的计数,则将最高的数字放在第一位。

[2,8,2,6,1,8,2,6,6] 
to
[6,6,6,2,2,2,8,8,1]

4 个答案:

答案 0 :(得分:5)

您正在寻找的是获取值的频率的方法。 只要值为Hashable,此函数就可以工作:

它扩展了ElementHashable的所有序列类型,因此Int数组将起作用。

extension SequenceType where Generator.Element : Hashable {
    func frequencies() -> [Generator.Element:Int] {
        var results : [Generator.Element:Int] = [:]
        for element in self {
            results[element] = (results[element] ?? 0) + 1
        }
        return results
    }
}

然后你可以这样做:

let alpha = [2,8,2,6,1,8,2,6,6]

let sorted = alpha.frequencies().sort {
    if $0.1 > $1.1 { // if the frequency is higher, return true
        return true
    } else if $0.1 == $1.1 { // if the frequency is equal
        return $0.0 > $1.0 // return value is higher
    } else {
        return false // else return false
    }
}

更好的是,您现在可以为序列类型创建另一个扩展。 现在,他们需要符合Comparable以及Hashable

extension SequenceType where Generator.Element : protocol<Hashable,Comparable> {
    func sortByFrequency() -> [Generator.Element] {
        // the same sort function as before
        let sorted = self.frequencies().sort {
            if $0.1 > $1.1 {
                return true
            } else if $0.1 == $1.1 {
                return $0.0 > $1.0
            } else {
                return false
            }
        }
        // this is to convert back from the dictionary to an array
        var sortedValues : [Generator.Element] = []

        sorted.forEach { // for each time the value was found
            for _ in 0..<$0.1 {
                sortedValues.append($0.0) // append
            }
        }
        return sortedValues
    }
}

您对这一切的最终用法将如下所示:

let sorted = alpha.sortByFrequency() // [6, 6, 6, 2, 2, 2, 8, 8, 1]

超级清洁:)

如果您更喜欢接近sort本身的功能,您也可以使用此功能:

extension SequenceType where Generator.Element : Hashable {
    func sortedFrequency(@noescape isOrderedBefore: ((Self.Generator.Element,Int), (Self.Generator.Element,Int)) -> Bool) -> [Generator.Element] {

        let sorted = self.frequencies().sort {
            return isOrderedBefore($0,$1) // this uses the closure to sort
        }

        var sortedValues : [Generator.Element] = []

        sorted.forEach {
            for _ in 0..<$0.1 {
                sortedValues.append($0.0)
            }
        }
        return sortedValues
    }
}

上面的扩展程序在内部将数组转换为频率字典,并要求您输入返回closure的{​​{1}}。然后,您可以根据需要应用不同的排序。

因为您将带有排序逻辑的闭包传递给此函数,Bool的{​​{1}}不再需要具有可比性。

所有速记的备忘单:

Elements

排序:

SequenceType

答案 1 :(得分:3)

我不确定这是否是最有效的方式,但我认为它相当优雅:

extension Array where Element: Equatable {

    func subArrays() -> [[Element]] {
        if self.isEmpty {
            return [[]]
        } else {
            let slice = self.filter { $0 == self[0] }
            let rest = self.filter { $0 != self[0] }
            return rest.isEmpty 
                ? [slice]
                : [slice] + rest.subArrays()
        }
    }

    func sortByFrequency(secondarySort: ((Element, Element) -> Bool)? = nil) -> [Element] {
        return self.subArrays()
            .sort { secondarySort?($0[0], $1[0]) ?? false }
            .sort { $0.count > $1.count }
            .flatMap { $0 }
    }
}

let nums = [2,8,2,6,1,8,2,6,6]

print(nums.sortByFrequency(>))     // [6, 6, 6, 2, 2, 2, 8, 8, 1]

函数subArrays只是将数组分解为原始数组中每个值的子数组数组 - 即,您为所提供的输入获得[[2,2,2],[8,8],[6,6,6],[1]]

sortByFrequencysubArraysflatMap的输出进行排序以获得答案。

编辑:我修改了sortByFrequency以添加可选的secondarySearch参数。这使您可以控制您希望如何排序以相同频率发生的项目。或者,只接受默认的nil,它们不会按频率以外的任何其他方式进行排序。

此外,我修改了扩展程序,表明Element只需要符合Equatable,而不是Comparable

答案 2 :(得分:1)

//: Playground - noun: a place where people can play

import UIKit

var arr1 = [2,8,2,6,1,8,2,6,6]
var arr2 = [6,6,6,2,2,2,8,8,1]

var counting = [Int: Int]()

// fill counting dictionary
for num in arr1 {
    if counting[num] != nil {
        counting[num]!++
    } else {
        counting[num] = 1
    }
}

// [6: 3, 2: 3, 8: 2, 1: 1]
print(counting)

func order(i1: Int, i2: Int) -> Bool {
    let count1 = counting[i1]
    let count2 = counting[i2]

    // if counting is the same: compare which number is greater
    if count1 == count2 {
        return i1 > i2
    } else {
        return count1 > count2
    }
}

// [6, 6, 6, 2, 2, 2, 8, 8, 1]
print(arr1.sort(order))
print(arr2)

答案 3 :(得分:0)

在字典中使用grouping

var entries = [1,2,3,3,1,3,5,6,3,4,1,5,5,5,5]

extension Sequence where Element : Hashable {
    func byFrequency() -> [Element] {
        Dictionary(grouping: self, by: {$0}).sorted{ (a, b) in
            a.value.count > b.value.count
        }.map { $0.key}
    }
}


print(entries.byFrequency().first)

打印5