4

I have to filter an array having the most occurrences of element.

Initial Array :

let array1 = [1,2,3,2,4,2,5,3]
let array2 = ["abc", "def", "abc", "ert", "def", "abc"]

After Filtering, Final Array :

let filteredArray1 = [2,2,2]
let filteredArray2 = ["abc","abc","abc"]

I got the idea to get the count of elements from here:

Like getting the count of "abc" :

array2.filter{$0 == "abc"}.count

But is there any way to get the filtered array ?

Amit
  • 4,837
  • 5
  • 31
  • 46

2 Answers2

7

You can group the items into a dictionary and compare the number of items in each group

let mostFrequent = Dictionary(grouping: array1, by: {$0})
    .max(by: {$0.value.count < $1.value.count})?.value ?? []

The issue with the above is that if there are two or more values with the same count only one will be selected.

The below solution handles when there are multiple max counts, I couldn't write it as a single line expression though

let dictionary = Dictionary(grouping: array1, by: {$0})
let max = dictionary.max(by: {$0.value.count < $1.value.count})?.value.count ?? 0
let mostFrequent = dictionary.filter { $0.value.count == max }.values
Joakim Danielson
  • 43,251
  • 5
  • 22
  • 52
3

Using NSCountedSet

You can define this extension for the Array type

extension Array where Element: Equatable {

    func filteredByMostPopular() -> [Element] {
        let countedSet = NSCountedSet(array: self)
        let mostPopularElement = self.max { countedSet.count(for: $0) < countedSet.count(for: $1) }
        return self.filter { $0 == mostPopularElement }
    }

}

How does it work?

The extension uses NSCountedSet to find the "most popular" element.

If 2 or more elements are the most popular the first one is choosen.

Then the array is filtered using the most popular element.

Test

array1.filteredByMostPopular() // [2, 2, 2]
array2.filteredByMostPopular() // ["abc", "abc", "abc"]
Luca Angeletti
  • 58,465
  • 13
  • 121
  • 148