How to combine two arrays as a cartesian product?
Asked Answered
S

7

6

I have

array1 = [1,2,3,4,5];
array2 = ["one","two","three","four","five"];

I want to get array3 where all elements of array1 with first (and others) element of array2 and etc.

For example:

array3 = ["one 1", "two 1", "three 1", "four 1", "five 1", "one 2", "two 2", "three 2", "four 2", "five 2"...]

I understand that I need to use for loop but I don't know how to do it.

Squeak answered 16/1, 2016 at 10:51 Comment(1)
If you are underscore or lodash, a simple zipWith would work: _.zipWith(array1, array2, function(a,b) { return a + ' ' + b; });Soliloquy
B
11

You can use two for-loops:

var array1 = [1,2,3,4,5];
var array2 = ["one","two","three","four","five"];

var array3 = [];
for (var i = 0; i < array1.length; i++) {
    for (var j = 0; j < array2.length; j++) {
        array3.push(array2[j] + ' ' + array1[i]);
    }
}

console.log(array3);
Burnejones answered 16/1, 2016 at 10:57 Comment(0)
S
12

You can use Array.prototype.forEach() for the iteration over the arrays.

The forEach() method executes a provided function once per array element.

var array1 = [1, 2, 3, 4, 5],
    array2 = ["one", "two", "three", "four", "five"],
    result = [];

array1.forEach(function (a) {
    array2.forEach(function (b) {
        result.push(b + ' ' + a);
    });
});

document.write('<pre>' + JSON.stringify(result, 0, 4) + '</pre>');
Sateia answered 16/1, 2016 at 10:57 Comment(0)
B
11

You can use two for-loops:

var array1 = [1,2,3,4,5];
var array2 = ["one","two","three","four","five"];

var array3 = [];
for (var i = 0; i < array1.length; i++) {
    for (var j = 0; j < array2.length; j++) {
        array3.push(array2[j] + ' ' + array1[i]);
    }
}

console.log(array3);
Burnejones answered 16/1, 2016 at 10:57 Comment(0)
H
6

Yet another way with reduce and map and concat

Snippet based on @Nina Scholz

var array1 = [1, 2, 3, 4, 5],
    array2 = ["one", "two", "three", "four", "five"];

var result = array1.reduce(function (acc, cur) {
    return acc.concat(array2.map(function (name) {
        return name + ' ' + cur;
    }));
},[]);

document.write('<pre>' + JSON.stringify(result, 0, 4) + '</pre>');
Hyson answered 16/1, 2016 at 11:6 Comment(0)
D
5

There is still the option with loops:

var array2 = [1,2,3,4,5],
array1 = ["one","two","three","four","five"],
m = [];
for(var a1 in array1){  
  for(var a2 in array2){
      m.push( array1[a1]+ array2[a2] );    
  }
}
console.log(m);
Decompose answered 16/1, 2016 at 11:14 Comment(1)
P
3

You can use this method when array1.length and array2.length are equal.

var array1 = [1, 2, 3, 4, 5];
var array2 = ["one", "two", "three", "four", "five"];
var length = array1.length;
var array3 = new Array(Math.pow(length, 2)).fill(0).map((v, i) => array2[i % length] + ' ' + array1[i / length << 0]);


document.body.textContent = JSON.stringify(array3);
Plod answered 16/1, 2016 at 11:25 Comment(3)
what if array have different length?Hyson
@Hyson This question doesn't mention it.Plod
Yep, but I think you should add refinement that this work for array with same lengthsHyson
I
0

Try (JS)

function myFunction(){
            var F = [1, 2, 3, 4,5];
            var S = ["one", "two", "three", "four", "five"];
            var Result = [];

           var k=0;
            for (var i = 0; i < F.length; i++) {
                for (var j = 0; j < S.length; j++) {
                    Result[k++] = S[j] + " " + F[i];
                }
            }

            console.log(Result);
        }
Idempotent answered 16/1, 2016 at 11:15 Comment(2)
This is a JS question. The OP might be able to extrapolate code from this but I don't think it's useful.Kunstlied
Corrected it please checkIdempotent
S
0

Since this is not built into the language, here's a simple function with a similar signature to the built-in zip:

func cartesianProduct<Sequence1, Sequence2>(_ sequence1: Sequence1, _ sequence2: Sequence2) -> [(Sequence1.Element, Sequence2.Element)]
    where Sequence1 : Sequence, Sequence2 : Sequence
{
    var result: [(Sequence1.Element, Sequence2.Element)] = .init()
    sequence1.forEach { value1 in
        sequence2.forEach { value2 in
            result.append((value1, value2))
        }
    }
    return result
}

print(Array(zip([1, 2, 3], ["a", "b"]))) // [(1, "a"), (2, "b")]
print(cartesianProduct([1, 2, 3], ["a", "b"])) // [(1, "a"), (1, "b"), (2, "a"), (2, "b"), (3, "a"), (3, "b")]

In your case, you could do:

cartesianProduct([1,2,3,4,5], ["one","two","three","four","five"])
  .map { "\($0.1) \($0.0)" }

or even:

cartesianProduct(1...5, ["one","two","three","four","five"])
  .map { "\($0.1) \($0.0)" }

both of which will produce the sequence:

["one 1", "two 1", "three 1", "four 1", "five 1", "one 2", "two 2", "three 2", "four 2", "five 2", ...]

Since this is common to do on a collection's elements, I also created these two functional extensions:

extension Collection {
    /// O(n^2)
    func pairElementToEveryOtherElement() -> [(Self.Element, Self.Element)] {
        var result = [(Self.Element, Self.Element)]()
        for i in indices {
            var j = index(after: i)
            while j != endIndex {
                result.append((self[i], self[j]))
                j = index(after: j)
            }
        }
        return result
    }

    /// O(n)
    public func pairElementToNeighbors() -> [(Self.Element, Self.Element)] {
        if isEmpty {
            return .init()
        }

        var result: [(Self.Element, Self.Element)] = .init()
        var i = startIndex
        while index(after: i) != endIndex {
            result.append((self[i], self[index(after: i)]))
            i = index(after: i)
        }
        return result
    }
}

These can be used like follows:

let inefficientHasDuplicatesCheck = myCollection
  .pairElementToEveryOtherElement()
  .contains { $0.0 == $0.1 }
Slover answered 6/3, 2020 at 0:13 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.