I have a Hashmap<Long, List\<Foo>>
myMap. I want to remove an item from any List<Foo>
where the Foo.key
equals value assign to the key
variable.
Is there a good way to do this with streams? I am using the following code to delete the item, which doesn't seem the best to me:
for (List<Foo> l : myMap.values()) {
for (Foo f : l) {
if (f.getKey().equals(key)) {
l.remove(f);
break;
}
}
}
CodePudding user response:
Probably there are multiple ways to do this. Here is one:
myMap.values().forEach(list->list.removeIf(foo -> Objects.equals(foo.getKey(), key)));
The idea is to go over each list in the map and remove the elements that have the key you want to remove.
CodePudding user response:
The code you have is actually the most suitable tool for this task.
Since you need to modify the contents of the map, it means that you need a stream that will cause side effects. And that is discouraged by the documentation of the Stream API.
But you can enhance your code by using removeIf()
method added to the Collection
interface with Java-8.
public static void removeFooWithKey(Map<Long, List<Foo>> myMap,
String key) {
for (List<Foo> foos : myMap.values()) {
foos.removeIf(foo -> foo.getKey().equals(key));
}
}
CodePudding user response:
The simplest way is:
myMap.values().forEach(list -> list.removeIf(foo -> foo.getKey().equals(key)))
But removeIf removes all of the elements of this collection that satisfy the given predicate. It does not equal to your initial code. Probably if your collection consists of unique keys and you need to remove only one object removeIf
will do a little overhead and compare all elements of colections.
Solution 1. Remove by first matched index
myMap.values().forEach(list -> IntStream.range(0, list.size()).filter(index -> key.equals(list.get(index).getKey())).findFirst().ifPresent(list::remove))
Solution 2. Own removeFirstIf method
myMap.values().forEach(list -> StreamUtils.removeFirst(list, foo -> key.equals(foo.getKey())));
public class StreamUtils {
private StreamUtils() {
}
public static <T> T removeFirstIf(Iterable<? extends T> collection, Predicate<? super T> condition) {
Objects.requireNonNull(collection);
Objects.requireNonNull(condition);
T value;
final Iterator<? extends T> iterator = collection.iterator();
while (iterator.hasNext()) {
value = iterator.next();
if (condition.test(value)) {
iterator.remove();
return value;
}
}
return null;
}
}
Solution 3. Change your structure to Map<Long, Map<String, Foo>>
Assumption: probably if your List consists of unique keys then you can change your structure from Map<Long, List<Foo>>
to Map<Long, Map<String, Foo>>
Removing elements by Key
will be simple and fast:
Map<Long, Map<String, Foo>> myMapOfMaps = new HashMap<>();
myMapOfMaps.values().forEach(map -> map.remove(key));