【问题标题】:How do I check in Swift if two arrays contain the same elements regardless of the order in which those elements appear in?如果两个数组包含相同的元素,无论这些元素出现的顺序如何,我如何检查 Swift?
【发布时间】:2016-08-11 09:41:10
【问题描述】:

假设有两个数组...

var array1 = ["a", "b", "c"]
var array2 = ["b", "c", "a"]

我希望这两个数组的比较结果为真,以下...

var array1 = ["a", "b", "c"]
var array2 = ["b", "c", "a", "d"]

...是假的。我怎样才能在 Swift 中实现这一点?我试图将两个数组都转换为集合,但由于某种原因 Set() 不断删除数组包含的一些(通常是重复的)对象。

任何帮助将不胜感激。

【问题讨论】:

  • ["a","b"] 和 ["a", "a", "b"] 怎么样,他们应该比较 true 还是 false?
  • 假,但 ["a", "a", "b"] 和 ["a", "b", "a"] 为真。
  • 只是为了评论 - “......但出于某种原因 Set() 不断删除一些(通常是重复的)对象” - 是的,那是因为,根据 定义,集合确实不包含重复项。

标签: arrays swift swift2


【解决方案1】:

斯威夫特 3、4

extension Array where Element: Comparable {
    func containsSameElements(as other: [Element]) -> Bool {
        return self.count == other.count && self.sorted() == other.sorted()
    }
}

// usage
let a: [Int] = [1, 2, 3, 3, 3]
let b: [Int] = [1, 3, 3, 3, 2]
let c: [Int] = [1, 2, 2, 3, 3, 3]

print(a.containsSameElements(as: b)) // true
print(a.containsSameElements(as: c)) // false

【讨论】:

  • 非常好,很可能我不会想出先对元素进行排序的想法。感谢所有回复的人。
  • 像魅力一样工作!拯救了我的一天:)
  • 感谢您提供优雅且易于重复使用的解决方案,但计数比较似乎没有必要。
  • @lzl 使用和不使用 count 子句的性能测量没有明显的性能差异。数组上的 == 操作(Swift 源代码)首先检查计数,然后逐个元素地比较数组。
  • @Marcy 我不知道,那么在那种情况下我想不出比较计数的理由
【解决方案2】:

你可以这样做:

  array1.sortInPlace()
  array2.sortInPlace()

  print(array1,array2)

  if array1 == array2 {
    print("equal")
  } else {
  print("not equal") 
  }

如果不想更改原始数组,我们可以这样做

 let sorted1 = array1.sort()
 let sorted2 = array2.sort()

  if sorted1 == sorted2 {
    print("equal")
  }else {
    print("not equal")
  }

【讨论】:

    【解决方案3】:

    使用Set

    let array1 = ["a", "b", "c"]
    let array2 = ["b", "c", "a", "c"]
    
    let set1 = Set(array1)
    let set2 = Set(array2)
    
    if (set1.count == set2.count && set1 == set2) { //if you compare big sets it is recommended to compare the count of items in the sets beforehand
        //they are identical
    }
    

    Set 实现了Hashable,因此任务是实现哈希函数以使用Set

    【讨论】:

    • 问题中描述了使用 Set 不起作用,因为数组可能包含重复项。
    • 你还得比较个数。
    • set 不适用于可以包含重复的数组,但只要程序员假设没有重复 - 与对两个数组进行排序的麻烦相比,Set 的速度简直就是神奇
    【解决方案4】:

    Swift 5.2 解决方案

    var array1 = ["a", "b", "c"]
    var array2 = ["b", "c", "a"]
    
    if array1.sorted() == array2.sorted() {
        print("array 1 & array 2 are same")
    }
    

    【讨论】:

      【解决方案5】:

      创建函数来比较它们:

      func containSameElements(var firstArray firstArray: [String], var secondArray: [String]) -> Bool {
          if firstArray.count != secondArray.count {
              return false
          } else {
              firstArray.sortInPlace()
              secondArray.sortInPlace()
              return firstArray == secondArray
          }
      }
      

      然后:

      var array1 = ["a", "a", "b"]
      var array2 = ["a", "b", "a"]
      
      var array3 = ["a", "b", "c"]
      var array4 = ["b", "c", "a", "d"]
      
      print(containSameElements(firstArray: array1, secondArray: array2)) //true
      print(containSameElements(firstArray: array3, secondArray: array4)) //false
      print(array1) //["a", "a", "b"]
      print(array2) //["a", "b", "a"]
      print(array3) //["a", "b", "c"]
      print(array4) //["b", "c", "a", "d"]
      

      【讨论】:

      • 通常布尔检查不应该改变它的参数。
      • 哦,我现在想起来了,Swift 对数组有心理调用约定。
      • 我不知道这个。你能举个例子吗?
      • 我认为它们是(或至少曾经是)写时复制,但构成写的内容有时令人惊讶。无论如何,您的代码都很好 - 您更改的是副本,而不是原始代码。
      • 你的意思是 var firstArray firstArray: [String] 应该是 Inout firstArray: [String]?
      【解决方案6】:

      这是一个解决方案,不需要元素为Comparable,而只需Equatable。它比排序答案效率低得多,因此如果您的类型可以设为 Comparable,请使用其中之一。

      extension Array where Element: Equatable {
          func equalContents(to other: [Element]) -> Bool {
              guard self.count == other.count else {return false}
              for e in self{
                guard self.filter{$0==e}.count == other.filter{$0==e}.count else {
                  return false
                }
              }
              return true
          }
      }
      

      【讨论】:

      • 如果元素为Hashable,则只能遍历Set(self)。
      【解决方案7】:

      Swift 4.1/Xcode 9.4 的解决方案:

      extension Array where Element: Equatable {
          func containSameElements(_ array: [Element]) -> Bool {
              var selfCopy = self
              var secondArrayCopy = array
              while let currentItem = selfCopy.popLast() {
                  if let indexOfCurrentItem = secondArrayCopy.index(of: currentItem) {
                      secondArrayCopy.remove(at: indexOfCurrentItem)
                  } else {
                      return false
                  }
              }
              return secondArrayCopy.isEmpty
          }
      }
      

      此解决方案的主要优点是它使用的内存比其他解决方案少(它总是只创建 2 个临时数组)。此外,它不需要Element 为Comparable,只需为Equatable。

      【讨论】:

        【解决方案8】:

        如果您的数组元素符合Hashable,您可以尝试使用袋子(它就像一个带有每个项目数量注册的集​​合)。这里我将使用这个基于Dictionary的数据结构的简化版本。此扩展有助于从 Hashable 数组创建包:

        extension Array where Element: Hashable {
            var asBag: [Element: Int] {
                return reduce(into: [:]) {
                    $0.updateValue(($0[$1] ?? 0) + 1, forKey: $1)
                }
            }
        }
        

        现在您需要从初始数组中生成 2 个袋子并进行比较。我把它包装在这个扩展中:

        extension Array where Element: Hashable {
            func containSameElements(_ array: [Element]) -> Bool {
                let selfAsBag = asBag
                let arrayAsBag = array.asBag
                return selfAsBag.count == arrayAsBag.count && selfAsBag.allSatisfy {
                    arrayAsBag[$0.key] == $0.value
                }
            }
        }
        

        此解决方案已使用 Swift 4.2/Xcode 10 进行测试。如果您当前的 Xcode 版本早于 10.0,您可以在 Xcode9to10Preparation 中找到 ArraySlice 的函数 allSatisfy。您可以使用 CocoaPods 安装此库。

        【讨论】:

          【解决方案9】:

          我知道这个问题很老,而且它也不想确定 array1 是否是 array2 的子集。但是,这适用于 Swift 5.3 和 Xcode 12.3:

          var array1 = ["a", "b", "c"]
          var array2 = ["b", "c", "a", "d"]
          
          print("array1 == array2? \(Set(array1) == Set(array2))")
          print("array1 subset to array2? \(Set(array1).isSubset(of: Set(array2)))")
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2012-08-21
            • 2023-03-18
            • 2012-05-17
            • 1970-01-01
            • 2019-08-24
            • 1970-01-01
            相关资源
            最近更新 更多