0

I'm looking for library function which returns any combination of n subset from the k set. For example I have a set {1,2,3,4,5} and I need any combination of 3 numbers included in this set. Order doesn't matter. So this function should returns:

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

I have tried to write it by myself, but unsuccesfully and I give up. It works only when I take 3 numbers from any set. Maybe someone knows library function for this issue.

Dawood ibn Kareem
  • 68,796
  • 13
  • 85
  • 101

3 Answers3

0

I do not know any library functions by heart but you could use the following solution:

import java.io.PrintStream;
import java.util.*;

public class CombinationCalc<T> {
    private void getSubsets(List<T> input, int length, int index, Set<T> currentSet, List<Set<T>> solution) {
        if (currentSet.size() == length) {
            solution.add(new HashSet<>(currentSet));
            return;
        }
        if (index == input.size()) {
            return;
        }
        T x = input.get(index);
        currentSet.add(x);
        getSubsets(input, length, index + 1, currentSet, solution);
        currentSet.remove(x);
        getSubsets(input, length, index + 1, currentSet, solution);
    }

    public List<Set<T>> getSubsets(List<T> input, int length) {
        List<Set<T>> solution = new ArrayList<>();
        getSubsets(input, length, 0, new HashSet<>(), solution);
        return solution;
    }

    public void printSolution(List<Set<T>> solution, PrintStream ps) {
        Iterator<Set<T>> solutionIterator = solution.iterator();
        ps.print("[");
        if (!solutionIterator.hasNext()) {
            ps.print("]");
        }
        while (solutionIterator.hasNext()) {
            Set<T> solutionEntry = solutionIterator.next();
            Iterator<T> setEntry = solutionEntry.iterator();
            ps.print("[");
            if (!setEntry.hasNext()) {
                ps.print("]");
            }
            while (setEntry.hasNext()) {
                T entry = setEntry.next();
                ps.print(entry);
                if (setEntry.hasNext()) {
                    ps.print(", ");
                } else {
                    ps.print("]");
                }
            }
            if (solutionIterator.hasNext()) {
                ps.print(", ");
            } else {
                ps.print("]");
            }
        }
        ps.println();
    }


    public static void main(String[] args) {
        CombinationCalc<Integer> calc = new CombinationCalc<>();
        List<Integer> input = Arrays.asList(1, 2, 3, 4, 5);
        List<Set<Integer>> solution = calc.getSubsets(input, 3);

        calc.printSolution(solution, System.out);
    }
}

It's based on amit's solution.

meisterplanlos
  • 123
  • 1
  • 6
0

This is a simple and short solution using streams:

import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.Set;

import static java.util.stream.Collectors.toSet;

public class MakeSubsets {
  static <T> Set<Set<T>> subsets(Set<T> set, int size) {
    if (size < 1) {
      return Collections.singleton(Collections.emptySet());
    }
    return set.stream()
          .flatMap(e -> subsets(remove(set, e), size - 1).stream().map(s -> add(s, e)))
          .collect(toSet());
  }

  static <T> Set<T> add(Set<T> set, T elem) {
    Set<T> newSet = new LinkedHashSet<>(set);
    newSet.add(elem);
    return newSet;
  }

  static <T> Set<T> remove(Set<T> set, T elem) {
    Set<T> newSet = new LinkedHashSet<>(set);
    newSet.remove(elem);
    return newSet;
  }

  public static void main(String[] args) {
    Set<Integer> set = new LinkedHashSet<>(Arrays.asList(1, 2, 3, 4, 5));
    System.out.println(subsets(set, 3));
  }
}

How it works: The method subsets produces the set of all subsets of given size.

In case of size < 1 it returns a set, containing only the empty set.

Otherwise for each element of the given set, it produces a new set without this selected element. Then it produces (recursively) the set of the subsets with size - 1 elements of this smaller set. It then adds the selected element to each set in the result. Therefore all sets in the result have the desired size.

The recursion terminates because in each recursion level the size will decrease by one, which will evenually be < 1.

The assumption here is that set.size() >= size and size >= 0.

Donat
  • 2,401
  • 1
  • 6
  • 16
0

I found here recursive solution: https://stackoverflow.com/a/16256122/10929764 but it only prints out combinations. I tried to modify it to return all combinations as an ArrayList, but it doesn't work. Here is code:

public ArrayList<String[]> comb2(ArrayList<String>arr, int len, int startPosition, String[] result, ArrayList<String[]> allResults){
    if (len == 0){
        System.out.println(Arrays.toString(result));
        allResults.add(result);
        return allResults;
    }
    for (int i = startPosition; i <= arr.size()-len; i++){
        result[result.length - len] = arr.get(i);
        comb2(arr, len-1, i+1, result,allResults);
    }
    return allResults;
}

It prints out properly all combinations:

[A, B, C] [A, B, D] [A, B, E] [A, C, D] [A, C, E] [A, D, E] [B, C, D] [B, C, E] [B, D, E] [C, D, E]

but when I print out allResults which was previously returned by comb2 method than I get:

[C, D, E] [C, D, E] [C, D, E] [C, D, E] [C, D, E] [C, D, E] [C, D, E] [C, D, E] [C, D, E] [C, D, E]