Reputation: 1379
What do I have to do if I would like to remove not only element my iterator points now, but also another one? Task is to write out pairs that sum up to some value (they are stored in HashSet set). Idea: iterate through the set, find second element that sum to what I need, write them out and remove from set both. What I mean, if my set is: [1,2,3] and int sum = 4, then I iterate through, find element 1st: 1, check 4 - 1 = 3, write out (1,3), and then I would like to remove 1 and 3 from the set so that only {2} left. I cannot do this that way of course:
while (itr.hasNext()) {
int elem = itr.next();
int toSum = sum - elem;
if (set.contains(toSum)) {
System.out.println("(" + elem + "," + toSum + ")");
}
itr.remove();
set.remove(toSum);
}
because of concurrent exception. I found out that solution:
while (itr.hasNext()) {
HashSet<Integer> notNeeded = new HashSet<Integer>();
int elem = itr.next();
if (notNeeded.contains(elem)) {
itr.remove();
}
else {
int toSum = sum - elem;
if (set.contains(toSum)) {
System.out.println("(" + elem + "," + toSum + ")");
notNeeded.add(toSum);
}
itr.remove();
}
}
but that does not look elegant and efficient (especially space efficient). Is there any better way to do this?
Upvotes: 0
Views: 52
Reputation: 632
Well, of course you cannot call Set.remove()
from within the Iterator
because of the concurrent exception, but you can break the iteration and remove it afterwards.
Integer toSumFound = null;
while (itr.hasNext()) {
int elem = itr.next();
int toSum = sum - elem;
if (set.contains(toSum)) {
toSumFound = toSum;
System.out.println("(" + elem + "," + toSum + ")");
itr.remove();
break;
}
}
set.remove(toSumFound); //Check for nulls if needed
Upvotes: 0
Reputation: 159096
I would suggest a second Set with the used values. You can then decide whether to actually remove them from the original set at the end, or not.
Set<Integer> set = new HashSet<>(Arrays.asList(1,2,3,4,5,6));
int target = 7;
Set<Integer> used = new HashSet<>();
for (Integer value1 : set) {
if (used.contains(value1))
continue; // already processed
Integer value2 = target - value1;
if (! value2.equals(value1) && set.contains(value2)) {
used.add(value1);
used.add(value2);
System.out.println("(" + value1 + "," + value2 + ")");
}
}
set.removeAll(used); // optional
By making it nondestructive, you can reuse the Set for other searches:
private static void listPairs(Set<Integer> set, int target) {
System.out.print(target + ": ");
Set<Integer> used = new HashSet<>();
for (Integer value1 : set)
if (! used.contains(value1)) {
Integer value2 = target - value1;
if (! value2.equals(value1) && set.contains(value2)) {
used.add(value1);
used.add(value2);
System.out.print("(" + value1 + "," + value2 + ")");
}
}
System.out.println();
}
public static void main(String[] args) {
Set<Integer> set = new HashSet<>(Arrays.asList(1,2,3,4,5,6));
listPairs(set, 7);
listPairs(set, 6);
listPairs(set, 5);
}
OUTPUT
7: (1,6)(2,5)(3,4)
6: (1,5)(2,4)
5: (1,4)(2,3)
Upvotes: 1