Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get list of common elements of 2 array in Swift?

Tags:

arrays

swift

I have two arrays:

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

How can I get the list of common items in those two array which gives

ouptput = ["mango", "blueberry"] 

I can't use if contains(array, string) as I want to compare 2 arrays.

like image 822
AAA Avatar asked Sep 07 '15 12:09

AAA


People also ask

What is .first in Swift?

first(where:) Returns the first element of the sequence that satisfies the given predicate.

How do I check if two arrays are equal in Swift?

To check if two arrays are equal in Swift, use Equal To == operator. Equal To operator returns a Boolean value indicating whether two arrays contain the same elements in the same order. If two arrays are equal, then the operator returns true , or else it returns false .

What is joined in Swift?

In Swift, we are allowed to join the elements of an array in a string using joined() function. This function creates a new string by concatenating all the elements of an array using a specified separator. We can also join all the elements of an array without any separator.


2 Answers

You can also use filter and contains in conjunction:

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 vs Array for a single computation of common elements

We consider the following code snippet:

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) 

I have made some (artificial) benchmarks with Int and short/long Strings (10 to 100 Characters) (all randomly generated). I always use array1.count == array2.count

I get the following results:

If you have more than critical #(number of) elements converting to a Set is preferable

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

Explanation of the results

Using the Array approach uses "Brute force"-search which has time complexity O(N^2) where N = array1.count = array2.count which is in contrast to the Set approach O(N). However the conversion from Array to Set and back is very expensive for large data which explains the increase of critical #elements for bigger data types.


Conclusion

For small Arrays with about 100 elements the Array approach is fine but for larger ones you should use the Set approach.

If you want to use this "common elements"-operation multiple times it is advisable to use Sets only if possible (the type of the elements has to be Hashable).

Final Remarks

A conversion from Array to Set is kind of expensive while the conversion from Set to Array is in contrast very inexpensive.

Using filter with .filter(array1.contains) is performance wise faster than .filter{ array1.contains($0) } since:

  • the last one creates a new closure (only once) whereas the first one passes only a function pointer
  • for the last one the call of the closure creates an additional stack frame which costs space and time (multiple times: O(N))
like image 187
Qbyte Avatar answered Oct 04 '22 08:10

Qbyte


Convert them to Set and use intersect() function:

let fruitsArray = ["apple", "mango", "blueberry", "orange"] let vegArray = ["tomato", "potato", "mango", "blueberry"] let fruitsSet = Set(fruitsArray) let vegSet = Set(vegArray) let output = Array(fruitsSet.intersection(vegSet)) 
like image 34
Mousavian Avatar answered Oct 04 '22 09:10

Mousavian