[英]How to compare Equatable in Swift
我有兩組這樣的兩個數組。 我從第三方獲得他們。
var array1 : [Any?]
var array2 : [Any?]
我知道這些數組中的對象類型(在編譯時)。 例如,第一個元素是String
,第二個是Int
。
我目前比較每組數組(請注意數組不是同類的)。
array1[0] as? String == array2[0] as? String
array1[1] as? Int == array2[1] as? Int
...
每個集合中存在不同類型的最大問題。 結果,我想說10組數組,每組有5個元素。 我不得不做10 * 5顯式轉換為特定類型和比較。
我希望能夠編寫一個可以比較兩個數組的公共方法(無需指定所有類型)
compareFunc(array1, array2)
我開始走下去了。 但是,我無法弄清楚我應該如何施放物體。 我試過Equatable
。 但是,swift並不喜歡直接使用它。 所以,這樣的事情不起作用
func compare(array1: [Any?], array2: [Any?]) {
for index in 0..<array1.count {
if (array1[index] as? Equatable != array2[index] as? Equatable) {
// Do something
}
}
}
此數組中的每個對象都是Equatable。 但是,我不確定如何在這種情況下使用它。
由於您的目標是比較(可選) Any
元素的數組,您可以構建一個函數,通過使用switch
塊嘗試將數組的元素向下轉換為“ 不同的已知類型”來執行逐元素比較。 第三方陣列“ 。 請注意,您無需指定與特定類型對應的元素位置(因為這可能在不同的數組集之間有所不同),只需指定任何給定元素可能具有的不同類型的詳盡集合。
這種功能的一個例子如下:
func compareAnyArrays(arr1: [Any?], _ arr2: [Any?]) -> Bool {
/* element-by-element downcasting (to known types) followed by comparison */
return arr1.count == arr2.count && !zip(arr1, arr2).contains {
/* note that a 'true' below indicates the arrays differ (i.e., 'false' w.r.t. array equality) */
if let v1 = $1 {
/* type check for known types */
switch $0 {
case .None: return true
case let v0 as String:
if let v1 = v1 as? String { return !(v0 == v1) }; return true
case let v0 as Int:
if let v1 = v1 as? Int { return !(v0 == v1) }; return true
/* ...
expand with the known possible types of your array elements
... */
case _ : return true
/* */
}
}
else if let _ = $0 { return true }
return false
}
}
或者,通過使用@Roman Sausarnes的compare(...)
輔助函數 (略微修改)使switch
塊變得不那么臃腫:答案
func compareAnyArrays(arr1: [Any?], _ arr2: [Any?]) -> Bool {
/* modified helper function from @Roman Sausarnes:s answer */
func compare<T: Equatable>(obj1: T, _ obj2: Any) -> Bool {
return obj1 == obj2 as? T
}
/* element-by-element downcasting (to known types) followed by comparison */
return arr1.count == arr2.count && !zip(arr1, arr2).contains {
/* note also that a 'true' below indicates the arrays differ
(=> false w.r.t. equality) */
if let v1 = $1 {
/* type check for known types */
switch $0 {
case .None: return true
case let v0 as String: return !compare(v0, v1)
case let v0 as Int: return !compare(v0, v1)
/* ...
expand with the known possible types of your array elements
... */
case _ : return true
/* */
}
}
else if let _ = $0 { return true }
return false
}
}
用法示例:
/* Example usage #1 */
let ex1_arr1 : [Any?] = ["foo", nil, 3, "bar"]
let ex1_arr2 : [Any?] = ["foo", nil, 3, "bar"]
compareAnyArrays(ex1_arr1, ex1_arr2) // true
/* Example usage #2 */
let ex2_arr1 : [Any?] = ["foo", nil, 2, "bar"]
let ex2_arr2 : [Any?] = ["foo", 3, 2, "bar"]
compareAnyArrays(ex2_arr1, ex2_arr2) // false
這是一個邊緣解決方案,但它應該減少您試圖避免的一些重復代碼:
func compareAnyArray(a1: [Any?], _ a2: [Any?]) -> Bool {
// A helper function for casting and comparing.
func compare<T: Equatable>(obj1: Any, _ obj2: Any, t: T.Type) -> Bool {
return obj1 as? T == obj2 as? T
}
guard a1.count == a2.count else { return false }
return a1.indices.reduce(true) {
guard let _a1 = a1[$1], let _a2 = a2[$1] else { return $0 && a1[$1] == nil && a2[$1] == nil }
switch $1 {
// Add a case statement for each index in the array:
case 0:
return $0 && compare(_a1, _a2, t: Int.self)
case 1:
return $0 && compare(_a1, _a2, t: String.self)
default:
return false
}
}
}
這不是最美麗的解決方案,但它會減少你必須編寫的代碼量,它應該適用於任何兩個[Any?]
,只要你知道索引0
的類型是一個Int
,並且索引1
處的類型是String
等...
Aaron Rasmussen的緊湊和Swift 5版本的優秀解決方案:
func compare(a1: [Any?], a2: [Any?]) -> Bool {
guard a1.count == a2.count else { return false }
func compare<T: Equatable>(obj1: Any, _ obj2: Any, t: T.Type) -> Bool {
return obj1 as? T == obj2 as? T
}
return a1.indices.reduce(true) {
guard let _a1 = a1[$1], let _a2 = a2[$1] else { return $0 && a1[$1] == nil && a2[$1] == nil }
switch $1 {
case 0: return $0 && compare(obj1: _a1, _a2, t: Int.self)
case 1: return $0 && compare(obj1: _a1, _a2, t: String.self)
case 2: return $0 && compare(obj1: _a1, _a2, t: <#TypeOfObjectAtIndex2#>.self)
default: return false
}
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.