如何在swift中获得2个数组的常用元素列表

我有两个数组:

fruitsArray = ["apple", "mango", "blueberry", "orange"] vegArray = ["tomato", "potato", "mango", "blueberry"] 

我怎样才能得到这两个数组中的常用项目列表

 ouptput = ["mango", "blueberry"] 

我不能使用, if contains(array, string)因为我想比较2个数组。 请帮忙

你不需要一个Set(如上面提到的评论)。

你可以使用一个通用函数,类似于苹果在Swift Tour中使用的函数, 从而避免了强制转换

 func anyCommonElements <T, U where T: SequenceType, U: SequenceType, T.Generator.Element: Equatable, T.Generator.Element == U.Generator.Element> (lhs: T, rhs: U) -> Bool { for lhsItem in lhs { for rhsItem in rhs { if lhsItem == rhsItem { return true } } } return false } 

这个函数可以接受任何两个数组(SequenceTypes),如果它们的任何元素是相同的,则返回true。

你可以简单地修改这个generics函数来打包一个string数组,然后返回。

比如像这样:

 func arrayOfCommonElements <T, U where T: SequenceType, U: SequenceType, T.Generator.Element: Equatable, T.Generator.Element == U.Generator.Element> (lhs: T, rhs: U) -> [T.Generator.Element] { var returnArray:[T.Generator.Element] = [] for lhsItem in lhs { for rhsItem in rhs { if lhsItem == rhsItem { returnArray.append(lhsItem) } } } return returnArray } 

像这样的用法:

 var one = ["test2", "dog", "cat"] var other = ["test2", "cat", "dog"] var result = arrayOfCommonElements(one,other) print(result) //prints [test2, dog, cat] 

这里增加的好处是这个函数也适用于所有相同types的数组。 所以后来如果你需要比较两个[myCustomObject]数组,一旦它们都符合equatable,你就全部设置了 ! (双关语意)

编辑:(对于非常见的元素),你可以做这样的事情

 func arrayOfNonCommonElements <T, U where T: SequenceType, U: SequenceType, T.Generator.Element: Equatable, T.Generator.Element == U.Generator.Element> (lhs: T, rhs: U) -> [T.Generator.Element] { var returnArray:[T.Generator.Element] = [] var found = false for lhsItem in lhs { for rhsItem in rhs { if lhsItem == rhsItem { found = true break } } if (!found){ returnArray.append(lhsItem) } found = false } for rhsItem in rhs { for lhsItem in lhs { if rhsItem == lhsItem { found = true break } } if (!found){ returnArray.append(rhsItem) } found = false } return returnArray } 

这个实现很丑陋。

您也可以使用filtercontains在一起:

 let fruitsArray = ["apple", "mango", "blueberry", "orange"] let vegArray = ["tomato", "potato", "mango", "blueberry"] // only Swift 1 let output = fruitsArray.filter{ contains(vegArray, $0) } // in Swift 2 and above let output = fruitsArray.filter{ vegArray.contains($0) } // or let output = fruitsArray.filter(vegArray.contains) 

Set Array Set为单个计算常用元素

我们考虑下面的代码片段:

 let array1: Array = ... let array2: Array = ... // `Array` let commonElements = array1.filter(array2.contains) // vs `Set` let commonElements = Array(Set(array1).intersection(Set(array2))) // or (performance wise equivalent) let commonElements: Array = Set(array1).filter(Set(array2).contains) 

我用Int和short / long String (10到100个Character )(都是随机生成的)做了一些(人为的)基准。 我总是使用array1.count == array2.count

我得到以下结果:

如果你有更多的critical #(number of) elements转换成一个Set是最好的

 data | critical #elements -------------|-------------------- Int | ~50 short String | ~100 long String | ~200 

结果的解释

使用Array方法使用具有时间复杂度 O(N^2) “暴力”search,其中N = array1.count = array2.count ,这与Set方法O(N)相反。 然而,对于大数据来说,从Array到大数据的转换是非常昂贵的,这就解释了对于更大数据types的critical #elements的增加。


结论

对于具有大约100个元素的小型ArrayArray方法很好,但对于较大的Array ,您应该使用Set方法。

如果要多次使用这个“通用元素”操作,build议在可能的情况下使用Set (元素的types必须是Hashable )。

最后的评论

ArrayArray的转换是昂贵的,而从ArrayArray的转换相反却非常便宜。

使用.filter(array1.contains) filter性能比.filter{ array1.contains($0) }快,因为:

  • 最后一个创build一个新的闭包( 只有一次 ),而第一个只传递一个函数指针
  • 对于最后一个闭包的调用会创build一个额外的栈空间和时间( 多次O(N)

将它们转换为Set并使用intersect()函数:

 let fruitsArray = ["apple", "mango", "blueberry", "orange"] let vegArray = ["tomato", "potato", "mango", "blueberry"] let fruitsSet = Set(fruitsArray) let vegSet = Set(vegArray) let output = Array(fruitsSet.intersect(vegSet)) 

Swift 3.0

使用filter从两个数组中获取公共元素。

 let fruitsArray = ["apple", "mango", "blueberry", "orange"] let vegArray = ["tomato", "potato", "mango", "blueberry"] let newArray = fruitsArray.filter { (string) -> Bool in return vegArray.contains(string) } print(newArray) // OR /*let newArray = fruitsArray.filter{vegArray.contains($0)}*/ 

输出:

[“芒果”,“蓝莓”]

Swift编程语言(Swift 3)练习的一个通用方法是:

 func commonElements<T: Sequence, U: Sequence>(_ lhs: T, _ rhs: U) -> [T.Iterator.Element] where T.Iterator.Element: Equatable, T.Iterator.Element == U.Iterator.Element { var common: [T.Iterator.Element] = [] for lhsItem in lhs { for rhsItem in rhs { if lhsItem == rhsItem { common.append(lhsItem) } } } return common } 

你甚至可以比较数组内的对象,并过滤出常用数组

 struct myStruct { var userid:String; var details:String; init() { userid = "default value"; details = "default"; } }; var f1 = myStruct(); f1.userid = "1"; f1.details = "Good boy"; var f2 = myStruct(); f2.userid = "2"; f2.details = "Bad boy"; var f3 = myStruct(); f3.userid = "3"; f3.details = "Gentleman"; var arrNames1:Array = [f1,f3]; var arrNames2:Array = [f3,f1,f2]; let filteredArrayStruct = arrNames1.filter( { (user: myStruct) -> Bool in return arrNames2.contains({ (user1: myStruct) -> Bool in return user.userid == user1.userid; }) }) print(filteredArrayStruct)