如何比较两个对象数组?

15

我有一个A类:

class A {
   var identifier: String?
   var quantity: Int = 0
}

两个A实例的数组:

var array1: [A] = [a1, a2, a3, a4]
var array2: [A] = [a5, a6, a7, a8]

我不知道最好的检查方式是哪个:array1==array2 if a1.identifier == a5.identifier, a2.identifier == a6.identifier, a3.identifier==a7.identifier, a4.identifier==a8.identifier在Swift中。

请帮帮我...


@ddb:抱歉,它们的计数是随机的。 - Quang Hà
如果它们有不同的计数,那么它们应该被归类为不相等,对吗? - ddb
@Yannick:它们的内容是相同的,对不起我的英语不好。 - Quang Hà
那么 [a1, a2] == [a2, a1] 应该是 true 吗? - Yannick
@Yannick:是的,我想我不在意顺序... - Quang Hà
显示剩余4条评论
7个回答

27
您可以尝试这样做:

你可以像这样尝试:

let result = zip(array1, array2).enumerated().filter() {
    $1.0 == $1.1
}.map{$0.0}

@Rahul Tripathi,亲爱的Rahul Tripathi,你能解释一下你的代码吗?它很有趣,但我不理解。这是我的代码:let array1:[Int] = [1,2,3,4] let array2:[Int] = [5,6,7,8] let result = zip(array1,array2).enumerated().filter(){ $1.0 == $1.1 } .map {$ 0.0} print(result) - Naresh
7
即使这个代码能够运行,它看起来像是从某个地方复制粘贴而来的,没有任何关于代码的解释!@Rahul Tripathi - Aragunz
1
我认为这不是一个好的解决方案。它只适用于一种情况,即当两个数组按相同顺序排序时。 - Varun Goyal
3
这个答案是不正确的,因为在这种比较中 [1,2,3] 被视为等于 [1,2,3,4](zip 会选择最短数组的长度)。 - Vyachaslav Gerchicov

18

Swift 4

以下方法使得操作更为简便。

方法1 - 使用Equatable Protocol

步骤1 - 将您的类'A'设为可比较,如下所示

extension A: Equatable {
    static func ==(lhs: A, rhs: A) -> Bool {
        // Using "identifier" property for comparison
        return lhs.identifier == rhs.identifier
    }
}

第二步 - 按升序或降序排序您的数组

let lhsArray = array1.sorted(by: { $0.identifier < $1.identifier })
let rhsArray = array2.sorted(by: { $0.identifier < $1.identifier })

第三步 - 使用 == 或 elementsEqual 进行比较

let isEqual = lhsArray == rhsArray

或者

let isEqual = lhsArray.elementsEqual(rhsArray, by: { $0 == $1} )

方法二(不使用Equatable协议)

步骤1 - 如方法一中的步骤2所述,对数组进行排序

步骤2 - 使用elementsEqual方法

lhsArray.elementsEqual(rhsArray, by: { $0.identifier == $1.identifier })

阅读有关数组比较的更多信息


1
elementsEqual是一个非常好的小函数,以前从未遇到过,但正是我所需要的 :) - Leon
谢谢您的回复,@Anand。但是如果我想创建一个只包含相等对象的新数组,我该怎么做? - Erkam KUCET
1
@ErkamKUCET 你可以使用数组的 filter 方法。 - Anand
@Anand 好的,实际上我的问题是我有两个相同类型的数组,我想创建一个新的数组,其中包含这些数组中相同的元素。 - Erkam KUCET
@ErkamKUCET:你应该仔细阅读官方文档。有许多内置函数可供使用。如果你仍然找不到正确的方法,请在这里提出一个新问题。 - Anand

9
假设您的数据如下所示:

struct Person
    {
        let name: String
        let id:  Int
    }

    var people1 = [
        Person(name: "Quang Hà", id: 42),
        Person(name: "Lý Hải", id: 23),
        Person(name: "Maria", id: 99)
    ]

    var people2 = [
        Person(name: "Maria yyy", id: 99),
        Person(name: "Billy", id: 42),
        Person(name: "David", id: 23)
    ]

这是比较两个人员ID数组的方法:
func areArrayPeopleEqual(people1:[Person], people2: [Person]) -> Bool {
    var array1 = people1
    var array2 = people2

    // Don't equal size => false
    if array1.count != array2.count {
        return false
    }

    // sort two arrays
    array1.sortInPlace() { $0.id > $1.id }
    array2.sortInPlace() {$0.id > $1.id }

    // get count of the matched items
    let result = zip(array1, array2).enumerate().filter() {
        $1.0.id == $1.1.id
        }.count

    if result == array1.count {
        return true
    }

    return false
}

1
没有理由使用 .enumerate() 来获取匹配项目的计数,但是筛选器将类似于 { $0.0.id == $0.1.id } - Roman Roba

5

如果您需要比较一些参数,则可以使用此方法:

let difference = currentObjects
    .filter({ currentObject in
        !(newObjects
            .contains(where: { $0.identifier == currentObject.identifier }))
    })


4

我在https://www.hackingwithswift.com/example-code/language/how-to-find-the-difference-between-two-arrays上找到了一个非常简单的解决方案。

(意为:该链接提供了一种简单的方法来查找两个数组之间的差异。)
extension Array where Element: Hashable {
func difference(from other: [Element]) -> [Element] {
    let thisSet = Set(self)
    let otherSet = Set(other)
    return Array(thisSet.symmetricDifference(otherSet))
 }
}

let names1 = ["a1", "A4", "a3", "a4"]//["John", "Paul", "Ringo"]
let names2 = ["a1", "a5", "a4","a1.1"]//["Ringo", "George"]
let difference = names1.difference(from: names2)

3
首先,我们扩展Equatable类,以拥有DRY代码,如果两个数组始终具有相同的大小,或者至少第一个数组小于等于第二个数组,则可以使用此解决方案。
请注意,您正在使用可选项,可能需要在之前进行解包。
class A {
    var identifier: String?
    var quantity: Int = 0

    init(identifier: String, quantity: Int) {
        self.identifier = identifier
        self.quantity = quantity
    }
}

let a1: A = A(identifier: "1", quantity: 1)
let a2: A = A(identifier: "2", quantity: 2)
let a3: A = A(identifier: "3", quantity: 3)
let a4: A = A(identifier: "4", quantity: 4)

let a5: A = A(identifier: "1", quantity: 1)
let a6: A = A(identifier: "2", quantity: 2)
let a7: A = A(identifier: "3", quantity: 3)
let a8: A = A(identifier: "4", quantity: 4)

var array1: [A] = [a1, a2, a3, a4]
var array2: [A] = [a5, a6, a7, a8]

func areEquals(array1: [A], array2: [A]) -> Bool {
    if array1.count < array2.count {
        return false
    }
    for i in 0...array2.count - 1 {
        if array1[i] != array2[i] {
            return false
        }
    }
    return true
}


extension A: Equatable {
    static func ==(lhs: A, rhs: A) -> Bool {
        //you can choose how and when they should be equals
        return lhs.identifier == rhs.identifier
    }
}

Proof of working


1
尝试这段代码,如果有效请告诉我:

try this code, let me know if it works

func toDictionary<E, K, V>(
    array:       [E],
    transformer: (element: E) -> (key: K, value: V)?)
    -> Dictionary<K, V>
{
    return array.reduce([:]) {
        (var dict, e) in
        if let (key, value) = transformer(element: e)
        {
            dict[key] = value
        }
        return dict
    }
}

然后您可以执行以下类似的检查。
let areEqual = array1.count == array2.count;
if areEqual {
    let dict1 = toDictionary(array1) { ($0.identifier, $0.quantity) }
    let dict2 = toDictionary(array2) { ($0.identifier, $0.quantity) }
    areEqual = NSDictionary(dictionary: dict1).isEqualToDictionary(dict2)
}
print(areEqual)

免责声明:函数toDictionary已从这里获取。


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