Mix multiple strings into all the possible combinations

4.5k views Asked by At

I have some strings.

  1. 1

  2. 2

  3. 3

How do I combine them into all their unique combinations?

  1. 123

  2. 132

  3. 213

  4. 231

  5. 312

  6. 321

Here is the code I have, but I would like to work without the Random class because I understand that this is not the best way to do it.

import java.util.Random;

public class Solution
{
    public static void main(String[] args)
    {
        String[] names = new String[]{"string1", "string2", "string3"};
        for (int i = 0; i < 9; i++) {
            Random rand = new Random();
            int rand1 = rand.nextInt(3);
            System.out.println(names[rand.nextInt(3)] +
                    names[rand1] +
                    names[rand.nextInt(3)]);
        }
    }
}
3

There are 3 answers

3
Jordi Betting On BEST ANSWER

You can loop over the array by creating another nested loop for each repetition.

for (String word1 : words) {
    for (String word2 : words) {
        for (String word3 : words) {
            System.out.println(word1 + word2 + word3);
        }
    }
}

Here is how to avoid having the same word in one combination.

for (String word1 : words) {
    for (String word2 : words) {
        if ( !word1.equals(word2)) {
            for (String word3 : words) {
                if ( !word3.equals(word2) && !word3.equals(word1)) {
                    System.out.println(word1 + word2 + word3);
                }
            }
        }
    }
}

Here is a class version that is capable of multiple lengths, using backtracking.

import java.util.ArrayList;
import java.util.List;


public class PrintAllCombinations {

    public void printAllCombinations() {
        for (String combination : allCombinations(new String[] { "A", "B", "C" })) {
            System.out.println(combination);
        }
    }

    private List<String> allCombinations(final String[] values) {
        return allCombinationsRecursive(values, 0, values.length - 1);
    }

    private List<String> allCombinationsRecursive(String[] values, final int i, final int n) {
        List<String> result = new ArrayList<String>();
        if (i == n) {
            StringBuilder combinedString = new StringBuilder();
            for (String value : values) {
                combinedString.append(value);
            }
            result.add(combinedString.toString());
        }
        for (int j = i; j <= n; j++) {
            values = swap(values, i, j);
            result.addAll(allCombinationsRecursive(values, i + 1, n));
            values = swap(values, i, j); // backtrack
        }
        return result;
    }

    private String[] swap(final String[] values, final int i, final int j) {
        String tmp = values[i];
        values[i] = values[j];
        values[j] = tmp;
        return values;
    }

}

Please note that using the random method, it is never guaranteed that all combinations are being get. Therefore, it should always loop over all values.

0
simon.watts On

Firstly, there is nothing random in the result you are after - and Random.nextInt() will not give you unique permutations, or necessarily all permutations.

For N elements, there are N! (N-factorial) unique sequences - which I believe is what you are after. Therefore your three elements give six unique sequences (3! = 3 * 2 * 1).

This is because you have a choice of three elements for the first position (N), then a choice of the two remaining elements for the second position (N-1), leaving one unchosen element for the last position (N-2).

So, this means that you should be able to iterate over all permutations of the sequence; and the following code should do this for a sequence of 3 elements:

// Select element for first position in sequence...
for (int i = 0 ; i < 3 ; ++i)
{
    // Select element for second position in sequence...
    for (int j = 0 ; j < 3 ; ++j)
    {
        // step over indices already used - which means we
        // must test the boundary condition again...
        if (j >= i) ++j;
        if (j >= 3) continue;

        // Select element for third position in sequence...
        // (there is only one choice!)
        for (int k = 0 ; k < 3 ; ++k)
        {
            // step over indices already used, recheck boundary
            // condition...
            if (k >= i) ++k;
            if (k >= j) ++k;
            if (k >= 3) continue;

            // Finally, i,j,k should be the next unique permutation...
            doSomethingWith (i, j, k);
        }
    }
}

Now, big caveat that I have just written this OTH, so no guarentees. However, hopefully you can see what you need to do. Of course, this could and should be generalised to support arbitary set sizes, in which case you could populate an int[] with the indices for the sequence.

However, I guess that if you look around there will be some better algorithms for generating permutations of a sequence.

0
bcody On

You could use the Google Guava library to get all string permutations.

    Collection<List<String>> permutations = Collections2.permutations(Lists.newArrayList("string1", "string2", "string3"));
    for (List<String> permutation : permutations) {
        String permutationString = Joiner.on("").join(permutation);
        System.out.println(permutationString);
    }

Output:

string1string2string3
string1string3string2
string3string1string2
string3string2string1
string2string3string1
string2string1string3