Reputation: 23
I recently had this problem. This is my code
for(int i=1; i<=repeticiones;i++){
posiblesComunes.removeIf(p->!periodos.get(i).contains(p));
}
periodos is a List(Set(String))
, posiblesComunes is a Set(String)
What I need to do is get only the strings that are in all of the Set(String) in periodos. I tried to do that using a for, but I get the next message:
Local variable i defined in an enclosing scope must be final or effectively final
Is there any way to fix that? Or another way to get those elements? Thanks!
edit: Just an example
periodos = {("1-1-16","6-12-16"),("1-1-16","2-8-15"),("3-7-08","1-1-16")}
What I need to get is "1-1-16", the one in common.
edit2:
an example of periodosComunes (for the for loop):
periodosComunes = ("1-1-16","6-2-16")
Upvotes: 0
Views: 193
Reputation: 24528
How about this:
Set<String> periodosComunes = Set.of("1-1-16","6-2-16");
List<Set<String>> periodos = List.of(
Set.of("1-1-16","6-12-16"),
Set.of("1-1-16","2-8-15"),
Set.of("3-7-08","1-1-16")
);
List<String> result = periodosComunes.stream()
.filter(x -> periodos.stream()
.allMatch(y -> y.contains(x))
)
.collect(Collectors.toList());
// result = [1-1-16]
I used collection literals from Java 9 to save me some typing, but that's irrelevant to the solution.
Upvotes: 2
Reputation: 36401
That should work (if I understand well your needs):
import java.util.stream.*;
import java.util.*;
public class P {
public static void main(String []a) {
// Init.
Set<String> periodosComunes = new HashSet<>(); periodosComunes.add("1-1-16"); periodosComunes.add("6-2-16");
Set<String> s1 = new HashSet<>(); s1.add("1-1-16"); s1.add("6-12-16");
Set<String> s2 = new HashSet<>(); s2.add("1-1-16"); s2.add("2-8-15");
Set<String> s3 = new HashSet<>(); s3.add("1-1-16"); s3.add("3-7-08");
List<Set<String>> periodos = new ArrayList<>(); periodos.add(s1); periodos.add(s2); periodos.add(s3);
// Computes the set of commons...
Set<String> r = periodosComunes.stream().filter(p->periodos.stream().allMatch(s->s.contains(p))).collect(Collectors.toSet());
System.out.println(r);
}
}
The set of common periods initially in periodosCommunes
is in r
. Now you can use that set to remove appropriate ones in the original set if needed:
periodosComunes.removeIf(s->!r.contains(s));
Upvotes: 0
Reputation: 298153
You can not access the local variable i
from a lambda expression, because it gets modified during the loop. The simplest fix is to capture the current value of i
in another immutable variable:
for(int i=1; i<=repeticiones;i++) {
int finalI = i;
posiblesComunes.removeIf(p -> !periodos.get(finalI).contains(p));
}
Note that the variable of a for-each loop does not have this problem:
for(Set<String> set: periodos.subList(1, repeticiones))
posiblesComunes.removeIf(p -> !set.contains(p));
but in the end, you are overusing Java 8 features here. This operation can be done with the original Collections API since Java 2:
for(Set<String> set: periodos.subList(1, repeticiones))
posiblesComunes.retainAll(set);
which would also work with your original loop:
for(int i=1; i<=repeticiones; i++)
posiblesComunes.retainAll(periodos.get(i));
Here, you could also add a short-cut, as the set never grows, so if there are no common elements, you can stop once the set became empty
for(int i=1; i<=repeticiones && !posiblesComunes.isEmpty(); i++)
posiblesComunes.retainAll(periodos.get(i));
Upvotes: 3
Reputation: 70909
Not all lists provide iterators with the ability to remove their items; however, if you select the right kind of list, this is built into the Iterator
interface.
Iterator i = list.iterator();
while (i.hasNext()) {
if (i.next().equals(bad)) {
i.remove();
}
}
The simplicity of the solution is enough you might consider skipping the Stream based approach, and unlike some kinds of modifications, Iterator
removal will not throw a ConcurrentModificationException
.
Upvotes: 1