如何将CGPoint数组按出现频率排序

6

我看到了这篇文章,它展示了如何以以下方式获取数组中最常见的值,例如整数:

let myArray = [4, 4, 4, 3, 3, 3, 4, 6, 6, 5, 5, 2]

// Create dictionary to map value to count   
var counts = [Int: Int]()

// Count the values with using forEach    
myArray.forEach { counts[$0] = (counts[$0] ?? 0) + 1 }

// Find the most frequent value and its count with max(isOrderedBefore:)    
if let (value, count) = counts.max(isOrderedBefore: {$0.1 < $1.1}) {
    print("\(value) occurs \(count) times")
}

我想要针对一个CGPoints数组实现相同的结果,这有些不同。我尝试使用相同的代码,但是出现了错误:

Type 'CGPoint' does not conform to protocol 'Hashable'

在这一行
var counts = [CGPoint: Int]()

和一个错误

Value of type 'CGPoint' has no member '1'

在代码的某一行
if let (value, count) = counts.max(isOrderedBefore: {$0.1 < $1.1}) {

我该如何按照频率排列CGPoint数组,并打印出一个元组,其中包含值和出现次数?

1
这里有一些关于如何使CGPoint符合Hashable的想法:http://codereview.stackexchange.com/questions/148763/extending-cgpoint-to-conform-to-hashable。 - Martin R
如果坐标不是整数,则二进制浮点数的有限精度可能成为一个问题。例如,CGPoint(x:0.1 + 0.2,y:0)CGPoint(x:0.3,y:0)不同的 - Martin R
1
@MartinR 为什么不直接使用 CGPoint 的 debugDescription 来创建字典呢?var counts = [String: Int]() myArray.forEach { counts[$0.debugDescription] = (counts[$0.debugDescription] ?? 0) + 1 } if let (value, count) = counts.max(by: {$0.value < $1.value}) { print("\(value) 出现了 \(count) 次") } https://gist.github.com/leodabus/b109b2ca9633c44974399a771690fe1d - Leo Dabus
@LeoDabus:是的,你可以这样做,但那样就要依赖于未记录的debugDescription格式。而且计算字符串哈希值(据我所知)相对来说比较“昂贵”,使用从x/y坐标计算出的哈希值应该更快。 - Martin R
@MartinR 谢谢您 - Leo Dabus
1个回答

1
这行错误的含义是:无法将类型为“CGPoint”的对象用作字典的键,因此不能满足 'Hashable' 协议。Leo Dabus在评论中提到的解决方法应该可以很好地解决问题:将 CGPoint 对象的调试描述 (String) 用作字典 counts 的键。
var counts = [String: Int]() 

myArray.forEach { counts[$0.debugDescription] = (counts[$0.debugDescription] ?? 0) + 1 } 

if let (value, count) = counts.max(by: {$0.value < $1.value}) { 
  print("\(value) occurs \(count) times") 
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接