Home > database >  How to invocate nested loops one loop at a time?
How to invocate nested loops one loop at a time?

Time:12-24

I want to compare each element against all others like following. The number of variables like a, b, c is dynamic. However, each variable's array size is uniform.

let a = [1, 2, 3]
let b = [3, 4, 5]
let c = [4, 5, 6]

for i in a {
    for j in b {
        for k in c {
            /// comparison
        }
    }
}

Instead looping from start to finish at once, what would be a way to make each comparison on call? For example:

compare(iteration: 0)
/// compares a[0], b[0], c[0]

compare(iteration: 1)
/// compares a[0], b[0], c[1]

/// all the way to
/// compares a[2], b[2], c[2]

Or it could even be like following:

next()
/// compares a[0], b[0], c[0]

next()
/// compares a[0], b[0], c[1]

almost like an iterator stepping through each cycle dictated by my invocation.

CodePudding user response:

Let the number of arrays be n. And let the number of elements in each array, which is guaranteed the same for all of them, be k.

Then create an array consisting of the integers 0 through k-1, repeated n times. For example, in your case, n is 3, and k is 3, so generate the array

[0, 1, 2, 0, 1, 2, 0, 1, 2]

Now obtain all combinations of n elements of that array. You can do this using the algorithm at https://github.com/apple/swift-algorithms/blob/main/Guides/Combinations.md. Unique the result (by, for example, coercing to a Set and then back to an Array). This will give you a result equivalent, in some order or other, to

[[0, 1, 2], [0, 1, 0], [0, 1, 1], [0, 2, 0], [0, 2, 1], [0, 2, 2], [0, 0, 1], [0, 0, 2], [0, 0, 0], [1, 2, 0], [1, 2, 1], [1, 2, 2], [1, 0, 1], [1, 0, 2], [1, 0, 0], [1, 1, 2], [1, 1, 0], [1, 1, 1], [2, 0, 1], [2, 0, 2], [2, 0, 0], [2, 1, 2], [2, 1, 0], [2, 1, 1], [2, 2, 0], [2, 2, 1], [2, 2, 2]]

You can readily see that those are all 27 possible combinations of the numbers 0, 1, and 2. But that is exactly what you were doing with your for loops! So now, use those subarrays as indexes into each of your original arrays respectively.

So for instance, using my result and your original example, the first subarray [0, 1, 2] yields [1, 4, 6] — the first value from the first array, the second value from the second array, and the third value from the third array. And so on.

In this way you will have generated all possible n-tuples by choosing one value from each of your original arrays, which is the desired result; and we are in no way bound to fixed values of n and k, which was what you wanted to achieve. You will then be able to "compare" the elements of each n-tuple, whatever that may mean to you (you did not say in your question what it means).

In the case of your original values, we will get these n-tuples (expressed as arrays):

[1, 4, 6]
[1, 4, 4]
[1, 4, 5]
[1, 5, 4]
[1, 5, 5]
[1, 5, 6]
[1, 3, 5]
[1, 3, 6]
[1, 3, 4]
[2, 5, 4]
[2, 5, 5]
[2, 5, 6]
[2, 3, 5]
[2, 3, 6]
[2, 3, 4]
[2, 4, 6]
[2, 4, 4]
[2, 4, 5]
[3, 3, 5]
[3, 3, 6]
[3, 3, 4]
[3, 4, 6]
[3, 4, 4]
[3, 4, 5]
[3, 5, 4]
[3, 5, 5]
[3, 5, 6]

Those are precisely the triples of values you are after.


Actual code:

    // your original conditions
    let a = [1, 2, 3]
    let b = [3, 4, 5]
    let c = [4, 5, 6]

    let originals = [a, b, c]

    // The actual solution starts here. Note that I never use any hard
    // coded numbers.
    let n = originals.count
    let k = originals[0].count
    var indices = [Int]()
    for _ in 0..<n {
        for i in 0..<k {
            indices.append(i)
        }
    }
    let combos = Array(indices.combinations(ofCount: n))
    var combosUniq = [[Int]]()
    var combosSet = Set<[Int]>()
    for combo in combos {
        let success = combosSet.insert(combo)
        if success.inserted {
            combosUniq.append(combo)
        }
    }

    // And here's how to generate your actual desired values.
    for combo in combosUniq {
        var tuple = [Int]()
        for (outerIndex, innerIndex) in combo.enumerated() {
            tuple.append(originals[outerIndex][innerIndex])
        }
        print(tuple) // in real life, do something useful here
    }
}
  • Related