我有CGPoint
S中的數組數,如何獲得次重複CGPoint陣列的每個值
pointArray = [(532.7, 150.0), (66.6, 150.0), (129.2, 150.0), (129.2, 150.0), (301.2, 150.0), (444.2, 150.0), (532.7, 150.0), (532.7, 150.0), (532.7, 150.0)]
我怎樣才能得到重複每個點的次數?
我有CGPoint
S中的數組數,如何獲得次重複CGPoint陣列的每個值
pointArray = [(532.7, 150.0), (66.6, 150.0), (129.2, 150.0), (129.2, 150.0), (301.2, 150.0), (444.2, 150.0), (532.7, 150.0), (532.7, 150.0), (532.7, 150.0)]
我怎樣才能得到重複每個點的次數?
由於@Alexander在評論中說,你應該使用一個NSCountedSet
,你可以使用它像這樣:
let array = [
CGPoint(x: 532.7, y: 150.0),
CGPoint(x: 66.6, y: 150.0),
CGPoint(x: 129.2, y: 150.0),
CGPoint(x: 129.2, y: 150.0),
CGPoint(x: 301.2, y: 150.0),
CGPoint(x: 444.2, y: 150.0),
CGPoint(x: 532.7, y: 150.0),
CGPoint(x: 532.7, y: 150.0),
CGPoint(x: 532.7, y: 150.0)
]
let countedSet = NSCountedSet(array: array)
countedSet.count(for: array.last!) //returns 4
如果你不希望使用NSCountedSet
,您可以在每個點存儲在一個字典作爲關鍵,並將計數作爲值。棘手的是,CGPoint
不符合Hashable
,你可以做這樣的:
extension CGPoint:Hashable{
public var hashValue: Int {
let x = Double(self.x)
let y = Double(self.y)
return Int(((x + y)*(x + y + 1)/2) + y)
//this hash function may not be the best for your data
}
}
var map = [CGPoint:Int]()
for point in array {
if let count = map[point] {
map[point] = count + 1
} else {
map[point] = 1
}
}
map[array.last!]//returns 4
我覺得這是更好地使用NSCountedSet
鏈接到一個散列函數'NSCountedSet'需要'Hashable'爲好。我相信幕後的訣竅是這些值被轉換爲「NSValue」。 – Sulthan
'NSCountedSet'有兩個初始化: '方便市民的init(數組:[任何])'和' 方便市民的init(設置:設置
我覺得用CountedSet的是矯枉過正。我只能指望他們:
let points = [CGPoint(x: 532.7, y: 150.0), CGPoint(x: 66.6, y: 150.0), CGPoint(x: 129.2, y: 150.0), CGPoint(x: 129.2, y: 150.0), CGPoint(x: 301.2, y: 150.0), CGPoint(x: 444.2, y: 150.0), CGPoint(x: 532.7, y: 150.0), CGPoint(x: 532.7, y: 150.0), CGPoint(x: 532.7, y: 150.0)]
var d : [NSValue:Int] = [:]
for p in points {
let v = NSValue(cgPoint:p)
if let ct = d[v] {
d[v] = ct+1
} else {
d[v] = 1
}
}
// how many times does `points[0]` appear in `points`?
d[NSValue(cgPoint:points[0])] // 4
這是我認爲最好的方法。你也可以讓CGPoint Hashable返回相應的NSValue hashValue –
請注意,你可以從CGPoint投射到NSValue而不是創建一個新的對象 –
@LeoDabus是的,我認爲這是Swift 3.0.1中的全新內容,而且我還沒有習慣了。 – matt
我同意馬特認爲接受的解決方案看起來像是矯枉過正。我建議類似的方法,他拿了一個,但使用功能的風格:
let dictionary:[String:Int] = array.reduce([:]){
var dict = $0.0, key = String(describing: $0.1)
dict[key] = (dict[key] ?? 0) + 1
return dict
}
使用這種方法,與原有陣列,我們得到這樣的結果:
let pointArray:[(CGFloat, CGFloat)] = [(532.7, 150.0), (66.6, 150.0), (129.2, 150.0), (129.2, 150.0), (301.2, 150.0), (444.2, 150.0), (532.7, 150.0), (532.7, 150.0), (532.7, 150.0)]
let dictionary:[String:Int] = pointArray.reduce([:]){
var dict = $0.0, key = String(describing: $0.1)
dict[key] = (dict[key] ?? 0) + 1
return dict
}
print(dictionary) //output is ["(129.2, 150.0)": 2, "(66.6, 150.0)": 1, "(532.7, 150.0)": 4, "(444.2, 150.0)": 1, "(301.2, 150.0)": 1]
注在使用String(describing:)
作爲字典鍵允許這與元組在您的示例代碼,以及其它變化不一定CGPoint
或Hashable
情況下工作。這將給你一個Hashable
字典的密鑰,而不需要編寫自定義代碼; 然而,亞歷山大在下面的評論指出,這是不產生Hashable
值最高效的方式,如果您在操作上幾萬點以上,或者在一個循環中頻繁運行此操作,差別使用String(describing:)
與自定義函數來從你的觀點元組的哈希可能是顯著
使用'String(描述:)'作爲散列技術是不必要的昂貴且容易碰撞 – Alexander
@Alexander一般來說,是的。在這種情況下,使用'(CGFloat,CGFloat)'值的數組,它不應該相互碰撞,並且不能使元組成爲'Hashable'。在CGPoint上使用'Hashable'擴展或在'NSValue'中包裝'CGPoint'是在其他情況下可以替代的實現,但是這個答案提供了:1)算法的功能樣式2)工作的解決方案與OP的示例輸入一起,前面的答案都沒有涵蓋 –
當然,這會導致衝突。你用1'Int''hashValue'來代表'CGPoint'的2'Int's。沒有任何功能可以映射這些1:1。你的算法是好的,但是爲'CGPoint'定義的恰當的哈希函數會更好,而不是使用'String(描述:)' – Alexander
之間有一個看看'NSCountedSet' – Alexander
@LeoDabus因此,使它可哈希:) – Alexander
@LeoDabus當然是。它已經由馬丁爲你完成了:) – Alexander