Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get all possible combinations from two arrays?

I have the two arrays:

String[] operators = {"+", "-", "*"};
int[] numbers = {48, 24, 12, 6};

And I want to get all possible combination in a String format like this:

48+24+12+6
48+24+12-6
48+24+12*6
48+24-12+6
48+24-12-6
48+24-12*6
..........
48*24*12*6

This what I have tried:

for (int i = 0; i < operators.length; i++) {
    System.out.println(numbers[0] + operators[i] + numbers[1] +
            operators[i] + numbers[2] + operators[i] + numbers[3]);
}

But it only prints:

48+24+12+6
48-24-12-6
48*24*12*6

How to solve this?

This is not a duplicate because I don't want to get every two pairs of data, I want to get every combination in 4 pairs. The duplicate is different.

like image 968
Oleg Caralanski Avatar asked Dec 14 '18 13:12

Oleg Caralanski


People also ask

How can I create every combination possible for the contents of two arrays?

const arr1 = ["A","B","C"]; const arr2 = ["1","2","3"]; We are required to write a JavaScript function that takes in two such arrays of literals. The function should then combine each element of the first array with each element of the second array and push them into a new array.

How do you find all possible combinations?

To calculate combinations, we will use the formula nCr = n! / r! * (n - r)!, where n represents the total number of items, and r represents the number of items being chosen at a time. To calculate a combination, you will need to calculate a factorial.

How do you find all permutations of an array?

You take first element of an array (k=0) and exchange it with any element (i) of the array. Then you recursively apply permutation on array starting with second element. This way you get all permutations starting with i-th element.

How do you generate all possible combinations of a set of numbers in Java?

Use Recurrence to Generate All Possible Combinations in Java First, we create an empty array that will store the outputs. The idea is to fix elements one by one and then use recurrence. Finally, when the number of elements in the initial array becomes equal to the size of combinations, then we print the initial array.


4 Answers

Use a triple loop:

for (int i=0; i < operators.length; ++i) {
    for (int j=0; j < operators.length; ++j) {
        for (int k=0; k < operators.length; ++k) {
            System.out.println(numbers[0] + operators[i] + numbers[1] + operators[j] +
                numbers[2] + operators[k] + numbers[3]);
        }
    }
}

You essentially want to take the cross product of the operators vector (if it were a vector). In Java, this translates to a triply-nested set of loops.

like image 155
Tim Biegeleisen Avatar answered Oct 19 '22 04:10

Tim Biegeleisen


While @TimBiegeleisen solution would work like a charm, its complexity might be an issue. The better approach would be a code like this:

static void combinationUtil(
        int[] arr, int n, int r, int index, int[] data, int i) {
    // Current combination is ready to be printed, print it 
    if (index == r) {
        for (int j = 0; j < r; j++)
            System.out.print(data[j] + " ");
        System.out.println("");
        return;
    }

    // When no more elements are there to put in data[] 
    if (i >= n)
        return;

    // current is included, put next at next location 
    data[index] = arr[i];
    combinationUtil(arr, n, r, index + 1, data, i + 1);

    // current is excluded, replace it with next (Note that 
    // i+1 is passed, but index is not changed) 
    combinationUtil(arr, n, r, index, data, i + 1);
}
// The main function that prints all combinations of size r 
// in arr[] of size n. This function mainly uses combinationUtil() 
static void printCombination(int arr[], int n, int r) {
    // A temporary array to store all combination one by one 
    int data[] = new int[r];

    // Print all combination using temprary array 'data[]' 
    combinationUtil(arr, n, r, 0, data, 0);
}

Source: GeeksForGeeks and my IDE :)

like image 8
PradyumanDixit Avatar answered Oct 19 '22 04:10

PradyumanDixit


This sounds like a textbook case for a recursive solution:

public static void combineAndPrint(String[] pieces, String[] operators) {
    if (pieces.length < 1) {
        // no pieces? do nothing!
    } else if (pieces.length == 1) {
        // just one piece? no need to join anything, just print it!
        System.out.println(pieces[0]);
    } else {
        // make a new array that's one piece shorter
        String[] newPieces = new String[pieces.length - 1];
        // copy all but the first two pieces into it
        for (int i = 2; i < pieces.length; i++) {
            newPieces[i - 1] = pieces[i];
        }
        // combine the first two pieces and recurse
        for (int i = 0; i < operators.length; i++) {
            newPieces[0] = pieces[0] + operators[i] + pieces[1];
            combineAndPrint(newPieces, operators);
        }
    }
}

public static void main(String[] args) {
    String[] operators = {"+", "-", "*"};
    String[] numbers = {"48", "24", "12", "6"};
    combineAndPrint(numbers, operators);
}

Try it online!

BTW, to generalize this method so that you can do more things with the generated expressions than just printing them, I would recommend making it accept an extra Consumer<String> parameter. That is, you could rewrite the method declaration as:

public static void combine(String[] pieces, String[] operators, Consumer<String> consumer) {

and replace the System.out.println(pieces[0]) with consumer.accept(pieces[0]) and the recursive call to combineAndPrint(newPieces, operators) with combine(newPieces, operators, consumer). Then just call it from your main method e.g. as:

combine(numbers, operators, s -> System.out.println(s));

Try it online!

(Of course, doing it in this more flexible way requires a somewhat modern Java version — Java 8 or later, to be specific — whereas the first example I showed above should work on even ancient versions all the way down to Java 1.0. Maybe in some future version of Java we'll get proper support for coroutines and generators, like Python and Kotlin and even modern JS already have, and then we won't even need to pass the consumer around any more.)

like image 5
Ilmari Karonen Avatar answered Oct 19 '22 02:10

Ilmari Karonen


As already pointed out by findusl in his answer, the problem here is, strictly speaking, not to find any sort of "combination of two arrays". Instead, you basically just want to find all possible combinations of the available operators.

(The fact that you later want to "interveave" them with operands is rather unrelated to the core of the question)

So here is another option for solving this: You can create an iterable over all combinations of a certain number of elements from a certain set (in your case: the operators) and then simply combine the results with the other set (in your case: the operands).

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;

public class OperatorsTest {
    public static void main(String[] args) {
        String[] operators = {"+", "-", "*"};
        int[] numbers = {48, 24, 12, 6};

        CombinationIterable<String> iterable =
                new CombinationIterable<String>(3, Arrays.asList(operators));
        for (List<String> element : iterable) {
            System.out.println(interveave(element, numbers));
        }
    }

    private static String interveave(List<String> operators, int numbers[]) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < operators.size(); i++) {
            sb.append(numbers[i]);
            sb.append(operators.get(i));
        }
        sb.append(numbers[numbers.length - 1]);
        return sb.toString();
    }
}

class CombinationIterable<T> implements Iterable<List<T>> {
    private final List<T> input;
    private final int sampleSize;
    private final int numElements;

    public CombinationIterable(int sampleSize, List<T> input) {
        this.sampleSize = sampleSize;
        this.input = input;
        numElements = (int) Math.pow(input.size(), sampleSize);
    }

    @Override
    public Iterator<List<T>> iterator() {
        return new Iterator<List<T>>() {
            private int current = 0;
            private final int chosen[] = new int[sampleSize];

            @Override
            public boolean hasNext() {
                return current < numElements;
            }

            @Override
            public List<T> next() {
                if (!hasNext()) {
                    throw new NoSuchElementException("No more elements");
                }

                List<T> result = new ArrayList<T>(sampleSize);
                for (int i = 0; i < sampleSize; i++) {
                    result.add(input.get(chosen[i]));
                }
                increase();
                current++;
                return result;
            }

            private void increase() {
                int index = chosen.length - 1;
                while (index >= 0) {
                    if (chosen[index] < input.size() - 1) {
                        chosen[index]++;
                        return;
                    }
                    chosen[index] = 0;
                    index--;
                }
            }
        };
    }
}

The task resembles that of finding a set of operations that can be done with a certain number of operands and operators, and thus, this Q/A may be related. But whether or not things like associativity or commutativity should be considered here was not mentioned in the question.

like image 2
Marco13 Avatar answered Oct 19 '22 03:10

Marco13