0

I have written the following method to generate power set using Java 8 map function

public static List<List<Integer>> powerSet(List<Integer> arr){
        List<List<Integer>> powerSet = new ArrayList<>();
        powerSet.add(new ArrayList<>());
        if(arr.size <= 0)
            return powerSet;
        for(Integer elem:arr) {
            powerSet.stream().map(p -> addSubset(powerSet, p, elem)).collect(Collectors.toList());
        }
        return powerSet;
    }

public static List<List<Integer>> addSubset(List<List<Integer>> powerSet, List<Integer> p, int elem){
    List<Integer> newSubset = p;
    newSubset.add(elem);
    powerSet.add(newSubset);
    return powerSet;
}

I always get Concurrent Modification exception. How can I modify this code to generate power set of list?

David Brossard
  • 13,584
  • 6
  • 55
  • 88
code-geek
  • 441
  • 1
  • 8
  • 22

1 Answers1

2

You are modifying a list as you are iterating thru it. A couple of issues here.

  • don't use streams. It isn't appropriate or helpful.
  • make a copy of powerSet and the added list per cycle to avoid a CME.
List<Integer> list = new ArrayList<>(List.of(20,30,40,50));
List<List<Integer>> ret = powerSet(list);
ret.forEach(System.out::println);

Prints

[]
[20]
[30]
[20, 30]
[40]
[20, 40]
[30, 40]
[20, 30, 40]
[50]
[20, 50]
[30, 50]
[20, 30, 50]
[40, 50]
[20, 40, 50]
[30, 40, 50]
[20, 30, 40, 50]

The modified methods.

    
public static List<List<Integer>> powerSet(List<Integer> arr) {
    List<List<Integer>> powerSet = new ArrayList<>();
    powerSet.add(new ArrayList<>());
    if (arr.size() <= 0)
        return powerSet;
    for (Integer elem:arr) {
        for (List<Integer> lst : powerSet) {      // <-- instead of streams.
            powerSet = new ArrayList<>(powerSet); // <-- new copy here
            addSubset(powerSet, lst, elem);
        }
    }
    return powerSet;
}
    
public static void addSubset(
        List<List<Integer>> powerSet, List<Integer> p, int elem) {
    p = new ArrayList<>(p); // <-- new copy here
    p.add(elem);
    powerSet.add(p);
}
WJS
  • 36,363
  • 4
  • 24
  • 39
  • Thank you much. It works. Could you please make me understand how the new copy of list works fine and not produce CME? I believe there is trick in call by value and referenc. Also what would be the space complexity?Would it consume space more than O(N*2^N) ? – code-geek Jan 28 '21 at 05:01
  • 1
    You're not permitted to modify a list that you are iterating over. The enhanced for loop uses an interator to loop over the list since the list implements the `Iterable` interface. So when you make modifications it can throw the iterator out of sync with the list. One way to solve this is to copy the list and modify the copy. If you search on this site for Concurrent Modification Exception there are many answers that go into more detail. It does not consume more space (over the long term) because the GC will collect the other lists as long as no reference to them exists. – WJS Jan 28 '21 at 13:30
  • Thank you very much for the explanation. I think you have missed to quote the site u mentioned (If you search on this site for Concurrent Modification Exception). Could you please share the link? – code-geek Jan 29 '21 at 09:56