1

The following code works as expected:

private static void experiment() {
    final UUID[] uuids = new UUID[]{null, UUID.randomUUID()};
    final String[] names = new String[]{null, "", " ", "\t", "someName"};
    final String[] descrs = new String[]{null, "", " ", "\t", "someDescr"};

    final List<Arguments> allArguments = new ArrayList<>();
    Arrays.stream(uuids)
            .forEach(uuid -> Arrays.stream(names)
                    .forEach(name -> Arrays.stream(descrs)
                            .forEach(descr -> allArguments
                                    .add(Arguments.of(uuid, name, descr)))));
}

allArguments ends up with the following content (quasi-coded), consisting of 50 elements:

{
 {null, null, null},
 {null, null, ""},
 ...
 {68dc3afc-a13e-405f-a761-12169e73ecf6, "someName", "someDescr"}
}

However, I would like two changes:

  1. I want n arrays of source values instead of the hardcoded three ones (uuids, names, descrs)
  2. I want to solve the problem using streams in the following way:
final Collection<Arguments> allArguments = 
    <whatever>
    <whatever>
    ...
    .collect(<whatever>);

Could anybody come up with a suggestion to the problem?

0

2 Answers 2

2

Try this.

static Function<List<Object>, Stream<List<Object>>> add(Object[] a) {
    return list -> Arrays.stream(a).map(y -> {
        List<Object> n = new ArrayList<>(list);
        n.add(y);
        return n;
    });
}


static void experiment() {
    UUID[] a = {null, UUID.randomUUID()};
    String[] b = {null, "b"};
    Integer[] c = {100, 200};
    String[] d = {"X", "Y"};
    List<List<Object>> s = Stream.of(Arrays.asList())
        .flatMap(add(a))
        .flatMap(add(b))
        .flatMap(add(c))
        .flatMap(add(d))
        .collect(Collectors.toList());
    for (List<Object> e : s)
        System.out.println(e);
}

output:

[null, null, 100, X]
[null, null, 100, Y]
[null, null, 200, X]
[null, null, 200, Y]
[null, b, 100, X]
[null, b, 100, Y]
[null, b, 200, X]
[null, b, 200, Y]
[0c52b3ab-18b2-460e-ac1d-152db85a603d, null, 100, X]
[0c52b3ab-18b2-460e-ac1d-152db85a603d, null, 100, Y]
[0c52b3ab-18b2-460e-ac1d-152db85a603d, null, 200, X]
[0c52b3ab-18b2-460e-ac1d-152db85a603d, null, 200, Y]
[0c52b3ab-18b2-460e-ac1d-152db85a603d, b, 100, X]
[0c52b3ab-18b2-460e-ac1d-152db85a603d, b, 100, Y]
[0c52b3ab-18b2-460e-ac1d-152db85a603d, b, 200, X]
[0c52b3ab-18b2-460e-ac1d-152db85a603d, b, 200, Y]

Or you can also do like this.

static List<List<Object>> cartesianProduct(Object[]... arrays) {
    return Arrays.stream(arrays)
        .map(a -> add(a))
        .reduce(Stream.of(Arrays.asList()),
            (s, p) -> s.flatMap(p), (a, b) -> Stream.concat(a, b))
        .collect(Collectors.toList());
}

And

UUID[] a = {null, UUID.randomUUID()};
String[] b = {null, "b"};
Integer[] c = {100, 200};
String[] d = {"X", "Y"};
for (List<Object> list : cartesianProduct(a, b, c, d))
    System.out.println(list);
Sign up to request clarification or add additional context in comments.

2 Comments

If you could even equip the methods and functions with somewhat more sonorous variable names instead of a, b, s, p and n, then I will also get som spare time to play with my grand children... (The source array names of a, b, c and are quite OK, however! :-)
I strongly agree with you. Especially add is a terrible name. But I can't name it properly.
0

Using streams, you can first represent each array as a 2d array, assuming the lengths of the arrays are the same, and get a stream of 2d arrays, then reduce that stream to a single 2d array.

Try it online!

public static void main(String[] args) {
    String[] uuids = {null, "", "68dc3afc", "112b1030"};
    String[] names = {null, "", "someName", "anotherName"};
    String[] descrs = {null, "", "someDesrc", "anotherDesrc"};

    String[][] arr2d = mergeAndPermute(uuids, names, descrs);

    // output
    Arrays.stream(arr2d).map(Arrays::toString).forEach(System.out::println);
    //[null, null, null]
    //[, , ]
    //[68dc3afc, someName, someDesrc]
    //[112b1030, anotherName, anotherDesrc]
}
public static String[][] mergeAndPermute(String[]... arrays) {
    // assume that the lengths of the arrays are the same
    return Arrays
            // Stream<String[]>
            .stream(arrays)
            // represent each array as a 2d array
            // Stream<String[][]>
            .map(arr -> Arrays.stream(arr)
                    .map(str -> new String[]{str})
                    .toArray(String[][]::new))
            // reduce a stream of 2d arrays to a single 2d array
            // by sequentially concatenating rows of 2d arrays
            .reduce((arr2d1, arr2d2) -> IntStream
                    // iterate over the indexes of 2d arrays
                    .range(0, arr2d1.length)
                    // concatenate rows of 2d arrays
                    .mapToObj(i -> Stream
                            .concat(Arrays.stream(arr2d1[i]),
                                    Arrays.stream(arr2d2[i]))
                            .toArray(String[]::new))
                    // return a single 2d array
                    .toArray(String[][]::new))
            .orElse(null);
}

See also:
Convert a map of lists into a list of maps
Adding up all the elements of each column in a 2d array

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.