Get all possible combination of items in array without duplicate groups in Swift
Asked Answered
B

3

8

I'm trying to create an extension on Array where I can get all possible combinations of an array without generating duplicate groups, including a no item combination.

For example, for this array:

[1, 2, 3, 4]

The following possible combinations should be generated:

[[], [1], [2], [3], [4], [1, 2], [1, 3], [1, 4], [2, 3], [2, 4], [3, 4], [1, 2, 3], [1, 2, 4], [1, 3, 4], [2, 3, 4], [1, 2, 3, 4]]

Please note that none of the groups repeat themselves, i.e: if there is a group [1, 2] there is no other group: [2, 1].

This is the closest I've been able to get to a result:

public extension Array {

func allPossibleCombinations() -> [[Element]] {
    var output: [[Element]] = [[]]
    for groupSize in 1...self.count {
        for (index1, item1) in self.enumerated() {
            var group = [item1]
            for (index2, item2) in self.enumerated() {
                if group.count < groupSize {
                    if index2 > index1 {
                        group.append(item2)
                        if group.count == groupSize {
                            output.append(group)
                            group = [item1]
                            continue
                        }
                    }
                } else {
                    break
                }
            }
            if group.count == groupSize {
                output.append(group)
            }
        }
    }
    return output
}

}

But it is missing possible combination of items in the group size 3 (I only get back [1, 2, 3] and [2, 3, 4].

Much appreciated!

Brocket answered 10/5, 2018 at 2:44 Comment(3)
Maybe generate shuffled versions and apply the same method to each. This might help: #128204Spratt
Yes, that could help. Thank you!Brocket
Use a Set for the "no duplicates" behavior.Emeliaemelin
U
17

You can use flatMap also to combine them in one line.

extension Array {
    var combinationsWithoutRepetition: [[Element]] {
        guard !isEmpty else { return [[]] }
        return Array(self[1...]).combinationsWithoutRepetition.flatMap { [$0, [self[0]] + $0] }
    }
}
    
print([1,2,3,4].combinationsWithoutRepetition)
Untrimmed answered 10/5, 2018 at 5:19 Comment(1)
I prefer this answer because the results are returned in ascending order.Brocket
A
7
extension Array {
    var combinations: [[Element]] {
        if count == 0 {
            return [self]
        }
        else {
            let tail = Array(self[1..<endIndex])
            let head = self[0]

            let first = tail.combinations
            let rest = first.map { $0 + [head] }

            return first + rest
        }
    }
}

print([1, 2, 3, 4].combinations)
Allare answered 10/5, 2018 at 2:53 Comment(1)
Thank you Nader, this is exactly what I needed!Brocket
R
5

This is in Algorithms now.

import Algorithms

Array([1, 2, 3, 4].combinations(ofCount: 0...))
Reginiaregiomontanus answered 3/3, 2022 at 9:36 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.