Aymen Bromdhane Aymen Bromdhane - 1 month ago 14
Swift Question

Divide array into little arrays with the same elements

let's say I have an array this way :

[1,4,7,4,2,2,4,7,1,2]
.

I need a function that divides this array into arrays with the same elements so it shows a result as this in swift :

result = [[1,1],[4,4,4],[7,7],[2,2,2]]
.

How to do that in swift ? Thanks in advance

Answer

You can use a helper dictionary to categorize the values of your array into the appropriate bins. E.g.:

let arr = [1, 4, 7, 4, 2, 2, 4, 7, 1, 2]
var dict: [Int: [Int]] = [:]
arr.forEach { dict[$0] = (dict[$0] ?? []) + [$0] }
let inBins = dict.map{ $1 }.sorted{ $0.first ?? 0 < $1.first ?? 0 }
print(inBins) // [[1, 1], [2, 2, 2], [4, 4, 4], [7, 7]]

Or, make use of the general Sequence extension for the categorising part, as described in the accepted answer in thread linked to by @Hamish:

E.g.:

/* from http://stackoverflow.com/a/39388832/4573247:
   @mientus's Swift 3 translation of @oisdk's accepted answer */
public extension Sequence {
    func categorise<U : Hashable>(_ key: (Iterator.Element) -> U) -> [U:[Iterator.Element]] {
        var dict: [U:[Iterator.Element]] = [:]
        for el in self {
            let key = key(el)
            if case nil = dict[key]?.append(el) { dict[key] = [el] }
        }
        return dict
    }
}

let arr = [1, 4, 7 ,4, 2, 2, 4, 7, 1, 2]
let inBins = arr.categorise{ $0 }.map{ $1 }.sorted{ $0.first ?? 0 < $1.first ?? 0 }
print(inBins) // [[1, 1], [2, 2, 2], [4, 4, 4], [7, 7]]

No need for the bins to be sorted (as above)? The two options above are then reduced to (simply dropping the last sortin part):

// ... first alternative above
let inBins = dict.map{ $1 }

// ... 2nd alternative above
let inBins = arr.categorise{ $0 }.map{ $1 }