9

I have a List of elements (1, 2, 3), and I need to get the superset (powerset) of that list (without repeating elements). So basically I need to create a List of Lists that looks like:

{1}
{2}
{3}
{1, 2}
{1, 3}
{2, 3}
{1, 2, 3}

What is the best (simplicity > efficiency in this case, the list won't be huge) way to implement this? Preferably in Java, but a solution in any language would be useful.

user unknown
  • 32,929
  • 11
  • 72
  • 115
Steve
  • 3,819
  • 11
  • 41
  • 74
  • 1
    You want all subsets of that list. I'd suggest recursion. However, if you are dealing with, say, more than 30-40 elements, you won't be able to deal with the HUGE (over 1TB of data) you have. What is this used for? – Per Alexandersson Aug 26 '11 at 14:57
  • 2
    This data structure you're looking for is called a Powerset (the diffence being that it also contains an empty set). It's already been discussed on SO. – Mateusz Dymczyk Aug 26 '11 at 14:58
  • Thanks Zenzen for pointing me in the right direction...I found http://stackoverflow.com/questions/1670862/obtaining-powerset-of-a-set-in-java. – Steve Aug 26 '11 at 15:18
  • 1
    Those are not [permutations](http://en.wikipedia.org/wiki/Permutation), those are subsets. – job Aug 26 '11 at 15:20

7 Answers7

36

Use bitmasks:

int allMasks = (1 << N);
for (int i = 1; i < allMasks; i++)
{
    for (int j = 0; j < N; j++)
        if ((i & (1 << j)) > 0) //The j-th element is used
           System.out.print((j + 1) + " ");

    System.out.println();
}

Here are all bitmasks:

1 = 001 = {1}
2 = 010 = {2}
3 = 011 = {1, 2}
4 = 100 = {3}
5 = 101 = {1, 3}
6 = 110 = {2, 3}
7 = 111 = {1, 2, 3}

You know in binary the first bit is the rightmost.

Petar Minchev
  • 44,805
  • 11
  • 98
  • 117
  • This is very interesting...you're obviously a lot smarter than I am though - give me some time to wrap my mind around this....is N the number of elements in the original list? And am I mapping the objects in my list to integers? – Steve Aug 26 '11 at 15:08
  • @Steve - Yes, `N` is the number of elements - in your example above `N = 3`. Think in binary - the bit is 0 if the element is not used and the bit is 1 if the element is used. For example 5 = 101 in binary. This means `1` and `3` are used. `= {1, 3}` – Petar Minchev Aug 26 '11 at 15:47
  • I don't think this will work for moderately sized lists or above, the allMasks integer will overflow – mancini0 Dec 21 '20 at 15:15
  • @mancini0 - it will overflow after around 31 bits (2^31), which is the max for integer, and it is already a colossal number of 2 billion. If you need to print or iterate 2 billion numbers, there is something wrong :) – Petar Minchev Dec 22 '20 at 16:16
  • @PetarMinchev I agree :), my only use case was a practice interview problem where I needed to return all permutations of a size 50 list (2^50 permutations, 10^15 possibilites) subject to a predicate. I modified your solution to use big integer for this purpose. The modified version would produce the correct answer in 40 years or so, but at least the interviewer could not say it was an incorrect solution. Your solution is beautiful by the way. – mancini0 Dec 23 '20 at 17:07
1
import java.io.*;
import java.util.*;
class subsets
{
    static String list[];
    public static void process(int n)
    {
        int i,j,k;
        String s="";
        displaySubset(s);
        for(i=0;i<n;i++)
        {
            for(j=0;j<n-i;j++)
            {
                k=j+i;
                for(int m=j;m<=k;m++)
                {
                    s=s+m;
                }
                displaySubset(s);
                s="";
            }
        }
    }
    public static void displaySubset(String s)
    {
        String set="";
        for(int i=0;i<s.length();i++)
        {
            String m=""+s.charAt(i);
            int num=Integer.parseInt(m);
            if(i==s.length()-1)
                set=set+list[num];
            else
                set=set+list[num]+",";
        }
        set="{"+set+"}";
        System.out.println(set);
    }
    public static void main()
    {
        Scanner sc=new Scanner(System.in);
        System.out.println("Input ur list");
        String slist=sc.nextLine();
        int len=slist.length();
        slist=slist.substring(1,len-1);
        StringTokenizer st=new StringTokenizer(slist,",");
        int n=st.countTokens();
        list=new String[n];
        for(int i=0;i<n;i++)
        {
            list[i]=st.nextToken();
        }
        process(n);
    }
}
greg-449
  • 102,836
  • 220
  • 90
  • 127
  • The program is simple. First, we try to get all possible combinations of 1-n digit numbers till the last digit of each list of 1,2,3,....n digit number is n. And then with each combination to extract each of its character(i.e. number) and display the element of the subset stored in the cell index denoted by this character(number). – Shraddha Gupta Dec 24 '13 at 08:32
  • It would be better to add the description of the code in the answer itself than in comments. Answer with code only are not considered good answer by the community in general, even the code answers properly the question. – рüффп Dec 26 '13 at 10:33
1

A java solution based on Petar Minchev solution -

public static List<List<Integer>> getAllSubsets(List<Integer> input) {
    int allMasks = 1 << input.size();
    List<List<Integer>> output = new ArrayList<List<Integer>>();
    for(int i=0;i<allMasks;i++) {
        List<Integer> sub = new ArrayList<Integer>();
        for(int j=0;j<input.size();j++) {
            if((i & (1 << j)) > 0) {
                sub.add(input.get(j));
            }
        }
        output.add(sub);
    }

    return output;
}
Nati Dykstein
  • 1,150
  • 9
  • 19
0

I've noticed that answers are focused on the String list. Consequently, I decided to share more generic answer. Hope it'll be fouund helpful. (Soultion is based on another solutions I found, I combined it to a generic algorithem.)

/**
 * metod returns all the sublists of a given list
 * the method assumes all object are different
 * no matter the type of the list (generics)
 * @param list the list to return all the sublist of
 * @param <T>
 * @return list of the different sublists that can be made from the list object
 */
public static <T>  List<List<T>>getAllSubLists(List<T>list)
{
    List<T>subList;
    List<List<T>>res = new ArrayList<>();
    List<List<Integer>> indexes = allSubListIndexes(list.size());
    for(List<Integer> subListIndexes:indexes)
    {
        subList=new ArrayList<>();
        for(int index:subListIndexes)
            subList.add(list.get(index));
        res.add(subList);
    }
    return res;
}
/**
 * method returns list of list of integers representing the indexes of all the sublists in a N size list
 * @param n the size of the list
 * @return list of list of integers of indexes of the sublist
 */
public static List<List<Integer>> allSubListIndexes(int n) {
    List<List<Integer>> res = new ArrayList<>();
    int allMasks = (1 << n);
    for (int i = 1; i < allMasks; i++)
    {
        res.add(new ArrayList<>());
        for (int j = 0; j < n; j++)
            if ((i & (1 << j)) > 0)
                res.get(i-1).add(j);

    }
    return res;
}
0

This is the simple function can be used to create a list of all the possible numbers generated by digits of all possible subsets of the given array or list.

void SubsetNumbers(int[] arr){
    int len=arr.length;
    List<Integer> list=new ArrayList<Integer>();
    List<Integer> list1=new ArrayList<Integer>();
    for(int n:arr){
        if(list.size()!=0){
            for(int a:list){
                list1.add(a*10+n);
            }
            list1.add(n);
            list.addAll(list1);
            list1.clear();
        }else{
            list.add(n);
        }
    }
    System.out.println(list.toString());
}
Tim Diekmann
  • 5,740
  • 9
  • 30
  • 53
Devashish
  • 141
  • 3
  • 7
0

In the given solution we iterate over every index and include current and all further elements.

class Solution {
        public List<List<Integer>> subsets(int[] nums) {
            List<List<Integer>> ans = new ArrayList<>();
            if(nums == null || nums.length ==0){
                return ans;
            }
            Arrays.sort(nums);
            List<Integer> subset = new ArrayList<>();
            allSubset(nums, ans , subset , 0);
            return ans;
        }
        private void allSubset(int[] nums,List<List<Integer>> ans ,List<Integer> subset , int idx){
            ans.add(new ArrayList<>(subset));
            for(int i = idx; i < nums.length; i++){
                subset.add(nums[i]);
                allSubset(nums, ans , subset , i+1);
                subset.remove(subset.size() - 1);
            }
        }
        
}
jizhihaoSAMA
  • 10,685
  • 9
  • 18
  • 36
0

Peter Minchev's solution modified to handle larger lists through BigInteger

public static List<List<Integer>> getAllSubsets(List<Integer> input) {
    BigInteger allMasks = BigInteger.ONE.shiftLeft(input.size());
    List<List<Integer>> output = new ArrayList<>();
    for(BigInteger i=BigInteger.ZERO;allMasks.subtract(i).compareTo(BigInteger.ZERO)>0; i=i.add(BigInteger.ONE)) {
        List<Integer> subList = new ArrayList<Integer>();
        for(int j=0;j<input.size();j++) {
            if(i.and(BigInteger.valueOf(1<<j)).compareTo(BigInteger.ZERO) > 0) {
                subList.add(input.get(j));
            }
        }
        System.out.println(subList);
        output.add(subList);
    }
    return output;
}
mancini0
  • 3,075
  • 21
  • 25