我需要在数组中找到最常见的(模态(元素。
我能想到的最简单的方法是为每个唯一元素设置变量,并为每个元素分配一个计数变量,每次记录在贯穿数组的 for 循环中时,计数变量都会增加。
不幸的是,数组的大小是未知的,并且会非常大,所以这种方法是无用的。
我在Objective-C中遇到了一个类似的问题,它使用NSCountedSet方法来对数组元素进行排名。不幸的是,我对编程很陌生,只能将第一行翻译成 Swift。
建议的方法如下:
var yourArray: NSArray! // My swift translation
NSCountedSet *set = [[NSCountedSet alloc] initWithArray:yourArray];
NSMutableDictionary *dict=[NSMutableDictionary new];
for (id obj in set) {
[dict setObject:[NSNumber numberWithInteger:[set countForObject:obj]]
forKey:obj]; //key is date
}
NSLog(@"Dict : %@", dict);
NSMutableArray *top3=[[NSMutableArray alloc]initWithCapacity:3];
//which dict obj is = max
if (dict.count>=3) {
while (top3.count<3) {
NSInteger max = [[[dict allValues] valueForKeyPath:@"@max.intValue"] intValue];
for (id obj in set) {
if (max == [dict[obj] integerValue]) {
NSLog(@"--> %@",obj);
[top3 addObject:obj];
[dict removeObjectForKey:obj];
}
}
}
}
NSLog(@"top 3 = %@", top3);
在我的程序中,我需要找到数组中的前五个地名。
编辑:现在下面有 Swift 2.0
不是最有效的解决方案,而是一个简单的解决方案:
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
现在由一组对组成:值和频率,排序最频繁。 因此,"前 5 名"将是前 5 个条目(假设有 5 个或更多不同的值(。 源数组有多大应该无关紧要。
下面是一个适用于任何序列的通用函数版本:
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)
对于 Swift 2.0,您可以将函数调整为协议扩展:
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()
对于 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 }
}
}
对于XCode 7.1,解决方案是。
// 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 descending = times.sort({$0.1 > $1.1})
// For sorting the keys the code would be
// let descending = times.sort({$0.0 > $1.0})
// Do whatever you want with sorted array
print(descending)
与空速速度相同,使用reduce
而不是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 }
}
}
但请注意,由于结构复制成本,在这里,将reduce
与struct
一起使用不如for-in
高效。因此,您通常更喜欢for-in
方式。
[编辑:天哪,这篇文章是同一个人写的,最高答案!