Outputs of rolling multiple dies and time complexity - java

I am working on this problem which seems very straigtforward:
For n number of dies return all the permutations.
Eg. n = 1, output = [[1],[2],[3],[4],[5],[6]]
Eg. n = 2, output = [[1, 1],[1, 2],[1, 3],[1, 4],[1, 5],[1, 6], [2, 1], ..... [6, 6]]
So I have solved it using recursion where the current solution uses previous results and builds on it:
public class Dice {
private static List<List<Integer>> getCombinations(int n) {
List<List<Integer>> result = new ArrayList<>();
// base cases
if (n == 0) {
return result;
}
if (n == 1) {
for (int i = 1; i <= 6; i++){
List<Integer> list = new ArrayList<>();
list.add(i);
result.add(list);
}
}
// general case
List<List<Integer>> prevResult = getCombinations(n - 1);
for (List<Integer> prevlist: prevResult){
for (int i = 1; i <= 6; i++){
List<Integer> list = new ArrayList<>(prevlist);
list.add(i);
result.add(list);
}
}
memo.put(n, result);
return result;
}
public static void main(String[] args) {
System.out.println("val = " + getCombinations(4));
}
}
I wanted to ask if I am right about the time complexity, which I think would be:
Time Complexity = O(b^d)
where b=branching factor and d=depth of recursion tree
= O(6^n)
Is this right?
Also I had 2 additional questions:
Is there a way I can memoize the above to reduce the time complexity?
Is there another better algorithm that I can use to solve this?

If you want to use an iterative approach rather than recursive, you could consider using a Deque:
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Deque;
import java.util.List;
/** Prints the permutations of rolling N dice with M faces. */
final class DiceRollPermutations {
private DiceRollPermutations() {}
public static void main(String[] args) {
if (args.length != 2) {
System.err.println("Usage: java DiceRollPermutations <numDice> <numFaces>");
System.exit(1);
}
int numDice = Integer.parseInt(args[0]);
int numFaces = Integer.parseInt(args[1]);
Deque<List<Integer>> diceRollPermutations = getDiceRollPermutations(numDice, numFaces);
System.out.printf(
"All possible permutations (%d) for rolling %d %s with %d %s:%n",
diceRollPermutations.size(),
numDice,
numDice == 1 ? "die" : "dice",
numFaces,
numFaces == 1 ? "face" : "faces");
for (List<Integer> permutation : diceRollPermutations) {
System.out.println(permutation);
}
}
public static Deque<List<Integer>> getDiceRollPermutations(int numDice, int numFaces) {
Deque<List<Integer>> permutations = new ArrayDeque<>();
permutations.offer(new ArrayList<Integer>());
for (int i = 1; i <= numDice; i++) {
int numPermutations = permutations.size();
for (int j = 1; j <= numPermutations; j++) {
List<Integer> perm = permutations.pollFirst();
for (int k = 1; k <= numFaces; k++) {
List<Integer> permClone = new ArrayList<>(perm);
permClone.add(k);
permutations.offer(permClone);
}
}
}
return permutations;
}
}
Example Usage 1:
$ java DiceRollPermutations 2 6
All possible permutations (36) for rolling 2 dice with 6 faces:
[1, 1]
[1, 2]
[1, 3]
[1, 4]
[1, 5]
[1, 6]
[2, 1]
[2, 2]
[2, 3]
[2, 4]
[2, 5]
[2, 6]
[3, 1]
[3, 2]
[3, 3]
[3, 4]
[3, 5]
[3, 6]
[4, 1]
[4, 2]
[4, 3]
[4, 4]
[4, 5]
[4, 6]
[5, 1]
[5, 2]
[5, 3]
[5, 4]
[5, 5]
[5, 6]
[6, 1]
[6, 2]
[6, 3]
[6, 4]
[6, 5]
[6, 6]
Example Usage 2:
$ java DiceRollPermutations 3 6
All possible permutations (216) for rolling 3 dice with 6 faces:
[1, 1, 1]
[1, 1, 2]
[1, 1, 3]
[1, 1, 4]
[1, 1, 5]
[1, 1, 6]
[1, 2, 1]
[1, 2, 2]
[1, 2, 3]
[1, 2, 4]
[1, 2, 5]
[1, 2, 6]
[1, 3, 1]
[1, 3, 2]
[1, 3, 3]
[1, 3, 4]
[1, 3, 5]
[1, 3, 6]
[1, 4, 1]
[1, 4, 2]
[1, 4, 3]
[1, 4, 4]
[1, 4, 5]
[1, 4, 6]
[1, 5, 1]
[1, 5, 2]
[1, 5, 3]
[1, 5, 4]
[1, 5, 5]
[1, 5, 6]
[1, 6, 1]
[1, 6, 2]
[1, 6, 3]
[1, 6, 4]
[1, 6, 5]
[1, 6, 6]
[2, 1, 1]
[2, 1, 2]
[2, 1, 3]
[2, 1, 4]
[2, 1, 5]
[2, 1, 6]
[2, 2, 1]
[2, 2, 2]
[2, 2, 3]
[2, 2, 4]
[2, 2, 5]
[2, 2, 6]
[2, 3, 1]
[2, 3, 2]
[2, 3, 3]
[2, 3, 4]
[2, 3, 5]
[2, 3, 6]
[2, 4, 1]
[2, 4, 2]
[2, 4, 3]
[2, 4, 4]
[2, 4, 5]
[2, 4, 6]
[2, 5, 1]
[2, 5, 2]
[2, 5, 3]
[2, 5, 4]
[2, 5, 5]
[2, 5, 6]
[2, 6, 1]
[2, 6, 2]
[2, 6, 3]
[2, 6, 4]
[2, 6, 5]
[2, 6, 6]
[3, 1, 1]
[3, 1, 2]
[3, 1, 3]
[3, 1, 4]
[3, 1, 5]
[3, 1, 6]
[3, 2, 1]
[3, 2, 2]
[3, 2, 3]
[3, 2, 4]
[3, 2, 5]
[3, 2, 6]
[3, 3, 1]
[3, 3, 2]
[3, 3, 3]
[3, 3, 4]
[3, 3, 5]
[3, 3, 6]
[3, 4, 1]
[3, 4, 2]
[3, 4, 3]
[3, 4, 4]
[3, 4, 5]
[3, 4, 6]
[3, 5, 1]
[3, 5, 2]
[3, 5, 3]
[3, 5, 4]
[3, 5, 5]
[3, 5, 6]
[3, 6, 1]
[3, 6, 2]
[3, 6, 3]
[3, 6, 4]
[3, 6, 5]
[3, 6, 6]
[4, 1, 1]
[4, 1, 2]
[4, 1, 3]
[4, 1, 4]
[4, 1, 5]
[4, 1, 6]
[4, 2, 1]
[4, 2, 2]
[4, 2, 3]
[4, 2, 4]
[4, 2, 5]
[4, 2, 6]
[4, 3, 1]
[4, 3, 2]
[4, 3, 3]
[4, 3, 4]
[4, 3, 5]
[4, 3, 6]
[4, 4, 1]
[4, 4, 2]
[4, 4, 3]
[4, 4, 4]
[4, 4, 5]
[4, 4, 6]
[4, 5, 1]
[4, 5, 2]
[4, 5, 3]
[4, 5, 4]
[4, 5, 5]
[4, 5, 6]
[4, 6, 1]
[4, 6, 2]
[4, 6, 3]
[4, 6, 4]
[4, 6, 5]
[4, 6, 6]
[5, 1, 1]
[5, 1, 2]
[5, 1, 3]
[5, 1, 4]
[5, 1, 5]
[5, 1, 6]
[5, 2, 1]
[5, 2, 2]
[5, 2, 3]
[5, 2, 4]
[5, 2, 5]
[5, 2, 6]
[5, 3, 1]
[5, 3, 2]
[5, 3, 3]
[5, 3, 4]
[5, 3, 5]
[5, 3, 6]
[5, 4, 1]
[5, 4, 2]
[5, 4, 3]
[5, 4, 4]
[5, 4, 5]
[5, 4, 6]
[5, 5, 1]
[5, 5, 2]
[5, 5, 3]
[5, 5, 4]
[5, 5, 5]
[5, 5, 6]
[5, 6, 1]
[5, 6, 2]
[5, 6, 3]
[5, 6, 4]
[5, 6, 5]
[5, 6, 6]
[6, 1, 1]
[6, 1, 2]
[6, 1, 3]
[6, 1, 4]
[6, 1, 5]
[6, 1, 6]
[6, 2, 1]
[6, 2, 2]
[6, 2, 3]
[6, 2, 4]
[6, 2, 5]
[6, 2, 6]
[6, 3, 1]
[6, 3, 2]
[6, 3, 3]
[6, 3, 4]
[6, 3, 5]
[6, 3, 6]
[6, 4, 1]
[6, 4, 2]
[6, 4, 3]
[6, 4, 4]
[6, 4, 5]
[6, 4, 6]
[6, 5, 1]
[6, 5, 2]
[6, 5, 3]
[6, 5, 4]
[6, 5, 5]
[6, 5, 6]
[6, 6, 1]
[6, 6, 2]
[6, 6, 3]
[6, 6, 4]
[6, 6, 5]
[6, 6, 6]

Related

Recursive number permutation in Java

Recently I got assigned an assignment that says this:
Write a program named NumberPermutation.java and implement a recursive method specified below:
public static void permutation(int num)
This method has a positive integer as its parameter and displays all permutations of the odd digits of that length.
Display these values in ascending order. For example, if the length is 3, your program should display:
111
113
115
117
119
131
133
135
...
I'm very new to Java (as in all my previous coding assignments for the past year have been in Python and this is the 3rd Java program I've worked on), so I am absolutely lost on where to even get started. If anyone can lend a hand and tell me how to get started I'd appreciate it, thanks.
Although I don't like questions that smell "help me with my homework" I'll provide an answer this time. Here's my suggestion. Please don't just copy and paste and hand in. Understand first, and use this example to understand some of the basics of Java.
public class RecursionTester {
public static void main(String[] args) {
new RecursionTester().permutation(3);
}
private void permutation(int num) {
permutation(num, "");
}
private void permutation(int num, String buffer) {
if (num == 0) {
System.out.println(buffer);
return;
}
for (int i = 1; i < 10; i += 2) {
permutation(num - 1, buffer + Integer.toString(i));
}
}
}
The fact that the results just go to System.out makes this solution pretty useless, but if the task is to only prove that you understand recursion it should be enough.
The map and reduce approach
You can interpret this task as getting the Cartesian product of the n-th number of 2D arrays of odd digits. If n=3 then you get 53=125 combinations.
The mapToObj method prepares 2D arrays for summation and points to the format of the result:
1: {{1}, {3}, {5}, {7}, {9}}
2: {{1}, {3}, {5}, {7}, {9}}
3: {{1}, {3}, {5}, {7}, {9}}
The reduce method sums pairs of 2D arrays into a single 2D array - two steps of reduction if n=3:
1: {{1}, {3}, {5}, {7}, {9}}
2: {{1}, {3}, {5}, {7}, {9}}
---
sum1: {{1, 1}, {1, 3}, {1, 5}, ...}
3: {{1}, {3}, {5}, {7}, {9}}
---
total: {1, 1, 1}, {1, 1, 3}, ...}
Try it online!
public static int[][] cartesianProduct(int n, int[][] arr) {
return IntStream.range(0, n)
// stream of n-th number of 2D arrays
.mapToObj(i -> arr)
// stream of 2D arrays into a single 2D array
.reduce((arr1, arr2) -> Arrays.stream(arr1)
// combinations of rows of two arrays
.flatMap(row1 -> Arrays.stream(arr2)
// concatenate into a single row
.map(row2 -> Stream.of(row1, row2)
.flatMapToInt(Arrays::stream)
// row of a 2D array
.toArray()))
// 2D array of combinations
.toArray(int[][]::new))
// otherwise an empty array
.orElse(new int[0][]);
}
public static void main(String[] args) {
// exponent
int n = 3;
// 2D array of odd digits
int[][] arr = {{1}, {3}, {5}, {7}, {9}};
// cartesian product
int[][] cp = cartesianProduct(n, arr);
// output
System.out.println("Number of combinations: " + cp.length);
// number of rows
int rows = cp.length / arr.length;
// column-wise output
IntStream.range(0, rows)
.mapToObj(i -> IntStream.range(0, cp.length)
.filter(j -> j % rows == i)
.mapToObj(j -> Arrays.toString(cp[j]))
.collect(Collectors.joining(" ")))
.forEach(System.out::println);
}
Output:
Number of combinations: 125
[1, 1, 1] [3, 1, 1] [5, 1, 1] [7, 1, 1] [9, 1, 1]
[1, 1, 3] [3, 1, 3] [5, 1, 3] [7, 1, 3] [9, 1, 3]
[1, 1, 5] [3, 1, 5] [5, 1, 5] [7, 1, 5] [9, 1, 5]
[1, 1, 7] [3, 1, 7] [5, 1, 7] [7, 1, 7] [9, 1, 7]
[1, 1, 9] [3, 1, 9] [5, 1, 9] [7, 1, 9] [9, 1, 9]
[1, 3, 1] [3, 3, 1] [5, 3, 1] [7, 3, 1] [9, 3, 1]
[1, 3, 3] [3, 3, 3] [5, 3, 3] [7, 3, 3] [9, 3, 3]
[1, 3, 5] [3, 3, 5] [5, 3, 5] [7, 3, 5] [9, 3, 5]
[1, 3, 7] [3, 3, 7] [5, 3, 7] [7, 3, 7] [9, 3, 7]
[1, 3, 9] [3, 3, 9] [5, 3, 9] [7, 3, 9] [9, 3, 9]
[1, 5, 1] [3, 5, 1] [5, 5, 1] [7, 5, 1] [9, 5, 1]
[1, 5, 3] [3, 5, 3] [5, 5, 3] [7, 5, 3] [9, 5, 3]
[1, 5, 5] [3, 5, 5] [5, 5, 5] [7, 5, 5] [9, 5, 5]
[1, 5, 7] [3, 5, 7] [5, 5, 7] [7, 5, 7] [9, 5, 7]
[1, 5, 9] [3, 5, 9] [5, 5, 9] [7, 5, 9] [9, 5, 9]
[1, 7, 1] [3, 7, 1] [5, 7, 1] [7, 7, 1] [9, 7, 1]
[1, 7, 3] [3, 7, 3] [5, 7, 3] [7, 7, 3] [9, 7, 3]
[1, 7, 5] [3, 7, 5] [5, 7, 5] [7, 7, 5] [9, 7, 5]
[1, 7, 7] [3, 7, 7] [5, 7, 7] [7, 7, 7] [9, 7, 7]
[1, 7, 9] [3, 7, 9] [5, 7, 9] [7, 7, 9] [9, 7, 9]
[1, 9, 1] [3, 9, 1] [5, 9, 1] [7, 9, 1] [9, 9, 1]
[1, 9, 3] [3, 9, 3] [5, 9, 3] [7, 9, 3] [9, 9, 3]
[1, 9, 5] [3, 9, 5] [5, 9, 5] [7, 9, 5] [9, 9, 5]
[1, 9, 7] [3, 9, 7] [5, 9, 7] [7, 9, 7] [9, 9, 7]
[1, 9, 9] [3, 9, 9] [5, 9, 9] [7, 9, 9] [9, 9, 9]
See also: How do I generate a Cartesian product in Java?

Heap's Algorithm implementation in list of lists

I'm using Heap's algorithm to create a list-of-lists containing each permutation of said list. Each permutation will be its own list. It works properly when I print it within the algorithm, but it doesn't work properly when I try to add it to my list-of-lists and they are all the same array (4, 1, 2, 3). I commented out the print that I tested to make sure it was working.
My current code:
public static ArrayList<int[]> lists = new ArrayList<>();
public static void main(String[] args) {
int[] list = {1,2,3,4};
heapsAlgorithm(4,list);
for(int i = 1; i <= lists.size(); i++) {
System.out.println("List " + i + ": " + Arrays.toString(lists.get(i-1)));
}
}
public static void heapsAlgorithm(int n, int[] list) {
if (n == 1) {
lists.add(list);
//System.out.println(Arrays.toString(list));
}
else {
for(int i = 0; i < n; i++) {
heapsAlgorithm(n - 1, list);
if ( n % 2 == 0) {
int swap = list[i];
list[i] = list[n-1];
list[n-1] = swap;
}
else {
int swap = list[0];
list[0] = list[n-1];
list[n-1] = swap;
}
}
}
}
Working:
[1, 2, 3, 4]
[2, 1, 3, 4]
[3, 1, 2, 4]
[1, 3, 2, 4]
[2, 3, 1, 4]
[3, 2, 1, 4]
[4, 2, 3, 1]
[2, 4, 3, 1]
[3, 4, 2, 1]
[4, 3, 2, 1]
[2, 3, 4, 1]
[3, 2, 4, 1]
[4, 1, 3, 2]
[1, 4, 3, 2]
[3, 4, 1, 2]
[4, 3, 1, 2]
[1, 3, 4, 2]
[3, 1, 4, 2]
[4, 1, 2, 3]
[1, 4, 2, 3]
[2, 4, 1, 3]
[4, 2, 1, 3]
[1, 2, 4, 3]
[2, 1, 4, 3]
Incorrect output:
List 1: [4, 1, 2, 3]
List 2: [4, 1, 2, 3]
List 3: [4, 1, 2, 3]
List 4: [4, 1, 2, 3]
List 5: [4, 1, 2, 3]
List 6: [4, 1, 2, 3]
List 7: [4, 1, 2, 3]
List 8: [4, 1, 2, 3]
List 9: [4, 1, 2, 3]
List 10: [4, 1, 2, 3]
List 11: [4, 1, 2, 3]
List 12: [4, 1, 2, 3]
List 13: [4, 1, 2, 3]
List 14: [4, 1, 2, 3]
List 15: [4, 1, 2, 3]
List 16: [4, 1, 2, 3]
List 17: [4, 1, 2, 3]
List 18: [4, 1, 2, 3]
List 19: [4, 1, 2, 3]
List 20: [4, 1, 2, 3]
List 21: [4, 1, 2, 3]
List 22: [4, 1, 2, 3]
List 23: [4, 1, 2, 3]
List 24: [4, 1, 2, 3]
I assume I am using my ArrayList wrong, but I'm not sure where. Any suggestions?
You are need to copy your int array.
You have an mutable instance of your array and list of arrays that you assume you to keep your permutations. Basically, what's happening:
You do permutation.
You add permutation to your ArrayList.
You do another permutation on THE SAME object.
You add object to ArrayList that ALREADY in this list.
At the end you have ArrayList with 20 times added the same int array.

How to find Sum of differences of maximum and minimum of all possible subset of an array

how to Find sum of maximum- minimum of all possible subset of given array
for example
given array is 1
all posible subsets are [[], [1]]
1-1=0
given array is 1 2
all posible subsets are [[], [1], [2], [1, 2]]
1-1+2-2+2-1=1
given array is 1 2 3
all posible subsets are [[], [1], [2], [1, 2], [3], [1, 3], [2, 3], [1, 2, 3]]
1-1+2-2+2-1+3-3+3-1+3-2+3-1=6
given array is 1 2 3 4
all posible subsets are [[], [1], [2], [1, 2], [3], [1, 3], [4], [2, 3], [1, 4], [1, 2, 3], [2, 4], [1, 2, 4], [3, 4], [1, 3, 4], [2, 3, 4], [1, 2, 3, 4]]
ans=23
given array is 2 3 4 5
all posible subsets are [[], [1], [2], [1, 2], [3], [1, 3], [4], [2, 3], [1, 4], [5], [1, 2, 3], [2, 4], [1, 5], [1, 2, 4], [3, 4], [2, 5], [1, 3, 4], [1, 2, 5], [3, 5], [2, 3, 4], [1, 3, 5], [4, 5], [1, 2, 3, 4], [2, 3, 5], [1, 4, 5], [1, 2, 3, 5], [2, 4, 5], [1, 2, 4, 5], [3, 4, 5], [1, 3, 4, 5], [2, 3, 4, 5], [1, 2, 3, 4, 5]]
ans= 72
First of all, sort the array then the i'th element will be minimum in all subsets that do not include the i-1 first elements, and include this element. There will be 2^(n-i) of those. In the same way, i will be the highest element in each subset that does not include any number after i, and include i, and there are 2^(i-1) such subsets.now iterate and for each i add:
sum = sum + array[i] * (2^(i) - 2^(n-i-1))
//if array starts with index array[0]
Consider your example: [1,2,3]
sorted=1,2,3
1* (2^0 - 2^2) + 2*(2^1 - 2^1) + 3*(2^2 - 2^0) =
1*(-3) + 2*0 + 3*(3) = -3 + 0 + 9 = 6

Combinations method return issue

I have written a method to find all combinations n choose k. When I have it void and simply print out the solutions it works fine. However, I am trying to change it as to return a List<List<Integer>> of all the combinations. I tried returning the solution and returning the recursion call in the if-else respectively but I get an error for unreachable line of code. Below I am trying to carry the list of list through the recursion and return it in the end.
public class Combos {
public static void main(String[] args) {
List<Integer> n = new ArrayList<Integer>();
for (int i = 0; i < 9; i++) {
n.add(i);
}
List<Integer> temp = new ArrayList<Integer>();
List<List<Integer>> combos = new ArrayList<List<Integer>>();
// findCombos(n, temp, 3, combos);
System.out.println(findCombos(n, temp, 3, combos));
}
public static List<List<Integer>> findCombos(List<Integer> n, List<Integer> temp, int k, List<List<Integer>> combos) {
if (k == 0) {
//System.out.print(temp);
combos.add(temp);
}
else {
for (int i = 0; i < n.size(); i++) {
temp.add(n.get(i));
List<Integer> subList = n.subList(i + 1, n.size());
findCombos(subList, temp, k - 1, combos);
temp.remove(temp.size() - 1);
}
}
return combos;
}
}
The working void method is here:
package client;
import java.util.ArrayList;
import java.util.List;
public class Combos {
public static void main(String[] args) {
List<Integer> n = new ArrayList<Integer>();
for (int i = 0; i < 5; i++) {
n.add(i);
}
List<Integer> temp = new ArrayList<Integer>();
findCombos(n, temp, 3);
}
public static void findCombos(List<Integer> n, List<Integer> temp, int k) {
if (k == 0) {
System.out.print(temp);
}
else {
for (int i = 0; i < n.size(); i++) {
temp.add(n.get(i));
List<Integer> subList = n.subList(i + 1, n.size());
findCombos(subList, temp, k - 1);
temp.remove(temp.size() - 1);
}
}
}
}
This has to do with the temp List and how it's always the same object when it gets added to combos.
Changing this line will correct that:
if (k == 0) {
combos.add(new ArrayList<Integer>(temp));
}
You have to make a copy because temp is getting mutated. After that, the output is:
[[0, 1, 2], [0, 1, 3], [0, 1, 4], [0, 1, 5], [0, 1, 6], [0, 1, 7], [0, 1, 8], [0, 2, 3], [0, 2, 4], [0, 2, 5], [0, 2, 6], [0, 2, 7], [0, 2, 8], [0, 3, 4], [0, 3, 5], [0, 3, 6], [0, 3, 7], [0, 3, 8], [0, 4, 5], [0, 4, 6], [0, 4, 7], [0, 4, 8], [0, 5, 6], [0, 5, 7], [0, 5, 8], [0, 6, 7], [0, 6, 8], [0, 7, 8], [1, 2, 3], [1, 2, 4], [1, 2, 5], [1, 2, 6], [1, 2, 7], [1, 2, 8], [1, 3, 4], [1, 3, 5], [1, 3, 6], [1, 3, 7], [1, 3, 8], [1, 4, 5], [1, 4, 6], [1, 4, 7], [1, 4, 8], [1, 5, 6], [1, 5, 7], [1, 5, 8], [1, 6, 7], [1, 6, 8], [1, 7, 8], [2, 3, 4], [2, 3, 5], [2, 3, 6], [2, 3, 7], [2, 3, 8], [2, 4, 5], [2, 4, 6], [2, 4, 7], [2, 4, 8], [2, 5, 6], [2, 5, 7], [2, 5, 8], [2, 6, 7], [2, 6, 8], [2, 7, 8], [3, 4, 5], [3, 4, 6], [3, 4, 7], [3, 4, 8], [3, 5, 6], [3, 5, 7], [3, 5, 8], [3, 6, 7], [3, 6, 8], [3, 7, 8], [4, 5, 6], [4, 5, 7], [4, 5, 8], [4, 6, 7], [4, 6, 8], [4, 7, 8], [5, 6, 7], [5, 6, 8], [5, 7, 8], [6, 7, 8]]
As an example of what is happening, if k is 1, we can follow the logic through for a couple of steps:
// k is 1 so call findCombos with 0
findCombos(subList, temp, k - 1, combos);
// k is 0 so add temp to combos
if (k == 0) {
combos.add(temp);
}
// on return, immediately mutate temp
temp.remove(temp.size() - 1);

Remove method of iterator doesn't work after the first call

I'm trying to group some sets in disjoint sets. For example, if I have these 5 sets:
[[1, 3], [2], [1, 5], [6, 8], [1, 7]]
I want to have this result:
[[2], [6, 8], [1, 3, 5, 7]]
Here is the code:
import java.util.*;
public class SetTest {
public static void main(String[] args) {
// ---- Initialisation
Set<Set<Integer>> groups = new LinkedHashSet<Set<Integer>>();
for (int[] set : new int[][] { {1, 3 }, {2 }, {1, 5 }, {6, 8 }, {1, 7} }) {
Set<Integer> group = new TreeSet<Integer>();
for (int i : set) {
group.add(i);
}
groups.add(group);
}
System.out.println(groups);
// ---- Grouping values in disjoint sets
for (Iterator<Set<Integer>> iterator = groups.iterator(); iterator.hasNext();) {
Set<Integer> group = iterator.next();
System.out.println(String.format(" + Checking %20s in \t %s", group, groups));
for (Set<Integer> other : groups) {
if (!group.equals(other) && !Collections.disjoint(group, other)) {
other.addAll(group);
iterator.remove();
System.out.println(String.format(" - Removed %20s -> \t %s", group, groups));
break;
}
}
}
System.out.println(groups);
}
}
I am using an iterator over the set, and I want to group 2 sets in one, removing one of them. However, I am having a problem with the Iterator.remove() method.
What this program prints is:
[[1, 3], [2], [1, 5], [6, 8], [1, 7]]
+ Checking [1, 3] in [[1, 3], [2], [1, 5], [6, 8], [1, 7]]
- Removed [1, 3] -> [[2], [1, 3, 5], [6, 8], [1, 7]]
+ Checking [2] in [[2], [1, 3, 5], [6, 8], [1, 7]]
+ Checking [1, 3, 5] in [[2], [1, 3, 5], [6, 8], [1, 7]]
- Removed [1, 3, 5] -> [[2], [1, 3, 5], [6, 8], [1, 3, 5, 7]]
+ Checking [6, 8] in [[2], [1, 3, 5], [6, 8], [1, 3, 5, 7]]
+ Checking [1, 3, 5, 7] in [[2], [1, 3, 5], [6, 8], [1, 3, 5, 7]]
- Removed [1, 3, 5, 7] -> [[2], [1, 3, 5, 7], [6, 8], [1, 3, 5, 7]]
[[2], [1, 3, 5, 7], [6, 8], [1, 3, 5, 7]]
The first time, removing [1, 3] works as expected, but the rest of the times, it does not remove the item. I think it's because I use addAll(), but why is that? Because I don't make changes in groups; I only change an element inside it(other) - and the reference is the same, right?
An element of a HashSet is supposed to have a stable hashCode, but you are mutating them as you iterate over the outer set. That fails in unpredictable, but documented ways.
In a TreeSet there may also be problems with changing the sort order of the element through mutation.

Categories