4

そのような2つの配列の複数のセットがあります。サードパーティから入手しています。

var array1 : [Any?]
var array2 : [Any?]

これらの配列内のオブジェクトのタイプについて知っています (コンパイル時)。例として、最初の要素は aStringで、2 番目の要素は anIntです。

私は現在、そのような配列の各セットを比較しています (配列は同種ではないことに注意してください)。

array1[0] as? String == array2[0] as? String
array1[1] as? Int == array2[1] as? Int
...

各セットに異なるタイプが含まれていることが最大の問題です。その結果、それぞれに 5 つの要素を持つ 10 セットの配列があると言えます。特定の型と比較に 10*5 の明示的な変換を行う必要がありました。

そのような2つの配列を比較できる共通のメソッドを記述できるようにしたい(すべての型を指定する必要はありません)

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 になります。ただし、この場合の使用方法はわかりません。

4

3 に答える 3

2

既知の要素型への (試行された) 型変換に基づいて、単純な要素ごとの比較関数を構築する

(オプションの)要素の配列を比較することを目的としているため、ブロックを使用して配列の要素を「サードパーティのさまざまな既知の型に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:s answerswitchのヘルパー関数を (わずかに変更して) 使用することで、ブロックの肥大化を少し減らします。compare(...)

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
于 2016-05-19T20:02:17.950 に答える
1

これは限界的な解決策ですが、回避しようとしている重複コードの一部を減らす必要があります。

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
        }
    }
}

これは最も美しい解決策ではありませんが、作成する必要があるコードの量が減り、 index の型が であり、 index の型が a であることがわかっている限り、任意の 2 に対して機能するはずです[Any?]。など...0Int1String

于 2016-05-19T18:27:31.433 に答える