有没有一种简单的方法可以按数字对数组进行排序?如果一个数字具有相同的计数,则将最高的数字放在第一位。
[2,8,2,6,1,8,2,6,6]
to
[6,6,6,2,2,2,8,8,1]
答案 0 :(得分:5)
您正在寻找的是获取值的频率的方法。
只要值为Hashable
,此函数就可以工作:
它扩展了Element
为Hashable
的所有序列类型,因此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]]
。
sortByFrequency
对subArrays
和flatMap
的输出进行排序以获得答案。
编辑:我修改了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