You don't need streams for this task, especially if you want to mutate the list of friends in-place:
students.forEach(s -> s.getFriends().removeAll(badKids));
And that's it. This uses the Collection.removeAll method.
Important: for this to work, the list of friends returned by the Student.getFriends() method must be mutable, such as ArrayList.
Despite the conciseness of the above solution, it breaks encapsulation, because we are mutating the list of friends of every student from outside the Student class. To fix this, you'd need to add a method to the Student class:
void removeBadKids(List<String> badKids) {
friends.removeAll(badKids);
}
Thus, the solution would now become:
students.forEach(s -> s.removeBadKids(badKids));
Answer from fps on Stack OverflowYou don't need streams for this task, especially if you want to mutate the list of friends in-place:
students.forEach(s -> s.getFriends().removeAll(badKids));
And that's it. This uses the Collection.removeAll method.
Important: for this to work, the list of friends returned by the Student.getFriends() method must be mutable, such as ArrayList.
Despite the conciseness of the above solution, it breaks encapsulation, because we are mutating the list of friends of every student from outside the Student class. To fix this, you'd need to add a method to the Student class:
void removeBadKids(List<String> badKids) {
friends.removeAll(badKids);
}
Thus, the solution would now become:
students.forEach(s -> s.removeBadKids(badKids));
You can do this:
List<Students> good = st.stream()
.peek(s -> s.getFriends().removeAll(bad))
.collect(Collectors.toList());
But using peek this way (should be used to log) is an anti-pattern, you can use map instead.
List<Students> good = st.stream()
.map(s -> {
s.getFriends().removeAll(bad);
return s;
})
.collect(Collectors.toList());
Remove Element in Nested List with Condition From another List - Java 8 - Stack Overflow
Filtering/removing from a nested List of Objects using streams in Java - Stack Overflow
java - Removing elements of one list if present in another list using stream - Stack Overflow
Remove elements from a list by iterating via stream Java 8 - Stack Overflow
Videos
To Remove element from the list
objectA.removeIf(x -> conditions);
eg:
objectA.removeIf(x -> blockedWorkerIds.contains(x));
List<String> str1 = new ArrayList<String>();
str1.add("A");
str1.add("B");
str1.add("C");
str1.add("D");
List<String> str2 = new ArrayList<String>();
str2.add("D");
str2.add("E");
str1.removeIf(x -> str2.contains(x));
str1.forEach(System.out::println);
OUTPUT: A B C
Although the thread is quite old, still thought to provide solution - using Java8.
Make the use of removeIf function. Time complexity is O(n)
producersProcedureActive.removeIf(producer -> producer.getPod().equals(pod));
API reference: removeIf docs
Assumption: producersProcedureActive is a List
NOTE: With this approach you won't be able to get the hold of the deleted item.
Since you need your lists to be updated, in the below solution I am using removeIf method of the List to remove any elements which does not meet the necessary criteria. So for removeIf to work, the list should not be immutable. So replace the var list = List.of(...) code with var list = new ArrayList<>(List.of(...));
(Note: Null checks have been ignored as well.)
Now, this problem could be split into components:
- Predicate to identify if a list has any odd elements.
Predicate<OneDObject> hasOdd = obj-> obj.getList().stream().anyMatch(i -> i % 2 != 0);
- Predicate to remove objects from 2d list, which has odd elements in its 1d list.
Predicate<TwoDObject> validate2d = obj -> {
// remove any 1d list that has atleast one odd number.
obj.getList().removeIf(hasOdd);
// check if there are any valid 1d lists
return obj.getList().isEmpty();
};
- Now apply the predicate to the final list:
l5.removeIf(validate2d); // l5 will now contain only the 2d object having [2,4,6] list
Here's the final code (in Java, but I think it should almost be interchangeable with Kotlin)
List<TwoDObject> l6 = l5.stream()
.peek(twoDObject -> {
List<OneDObject> filteredOneDObjectList = twoDObject.getList()
.stream()
.filter(oneDObject -> oneDObject.getList()
.stream()
.noneMatch(i -> i % 2 == 1))
.toList();
twoDObject.setList(filteredOneDObjectList);
})
.filter(twoDObject -> twoDObject.getList().size() > 0)
.toList();
First we go through every twoDObject by calling Stream#peek, then stream its list and filter out every oneDObject, which contains an odd number. Then the list is saved back into the current twoDObject.
In the end we filter out all empty twoDObjects.
Note that Stream#peek should normally only be used for the purpose of debugging and not mutating the stream elements.
In this case it could also be replaced with
List<TwoDObject> l6 = l5.stream()
.map(twoDObject -> {
...
return twoDObject;
})
...
If methods hashCode and equals are properly implemented in class Car, the stream-based solutions may look as follows:
- filter out the values, collect into a new list
// Predicate.not added in Java 11
List<Car> notJava11 = cars1.stream()
.filter(Predicate.not(cars2::contains))
.collect(Collectors.toList());
List<Car> notIn2 = cars1.stream()
.filter(car -> !cars2.contains(car))
.collect(Collectors.toList());
- Use
forEachforcars2(affectingcars1):
cars2.forEach(cars1::remove);
// no need to call cars2.stream().forEach(cars1::remove);
Here the first occurrence of Car instance is removed in cars1
removeIfshould work also
cars1.removeIf(cars2::contains);
If you due to some reason equals/hashCode are not overridden in class Car, the following solution may be offered:
List<Car> notIn2 = cars1
.stream()
.filter(c1 -> cars2
.stream()
.noneMatch(c2 ->
c1.getId() == c2.getId()
&& Objects.equals(c1.getName(), c2.getName())
)
)
.collect(Collectors.toList());
removeIf:
cars1.removeIf(c1 -> cars2
.stream()
.anyMatch(c2 -> c1.getId() == c2.getId()
&& Objects.equals(c1.getName(), c2.getName())
)
);
It can be done simply by using removeAll() method. You have to implement hashcode and equals in Car class.
Then you can cars1.removeAll(cars2);. this statement would leave only c1 in cars1 list.
I think you can do it with stream by using removeIf and some condition :
list.removeIf(h -> h.getTokens().contains("INC") &&
Arrays.stream(h.getTokens().split(";"))
.filter(tag -> tag.contains("INC"))
.map(tag -> tag.substring(tag.length() - 1))
.filter("N"::equals)
.anyMatch(v ->
(flag && !h.getPropertyA().equals(anotherObject.getPropertyAValue())) ||
(!flag && !h.getPropertyB().equals(anotherObject.getPropertyBValue()))));
Or you can separated the condition in a separated method, for example :
static void doAction(List<Hunt> list) {
list.removeIf(MyClass::isCorrect);
}
private static boolean isCorrect(Hunt h) {
return h.getTokens().contains("INC") &&
Arrays.stream(h.getTokens().split(";"))
.filter(tag -> tag.contains("INC"))
.map(tag -> tag.substring(tag.length() - 1))
.filter("N"::equals)
.anyMatch(v ->
(flag && !h.getPropertyA().equals(anotherObject.getPropertyAValue())) ||
(!flag && !h.getPropertyB().equals(anotherObject.getPropertyBValue())));
}
Or as @Tom Hawtin - tackline suggest, you can use :
static void doAction(List<Hunt> list) {
list.removeIf(h -> h.getTokens().contains("INC") &&
Arrays.stream(h.getTokens().split(";"))
.anyMatch(tag -> tag.contains("INC") && tag.endsWith("N")
&& !(flag ? h.getPropertyA().equals(anotherObject.getPropertyAValue())
: h.getPropertyB().equals(anotherObject.getPropertyBValue()))));
}
IMO stream API wont help you in this case! And this style of code is more readable in compared with stream based version. however I think you can make improvement by changing a bit.
Remove temporary variables such as
String[] tags = h.getTokens().split(";");andString value = tag.substring(tag.length() - 1);Combine some conditions with together.
Use
tag.charAt(tag.length() - 1)instead oftag.substring(tag.length() - 1);public static void doAction(List<Hunt> list) { for (ListIterator<Hunt> iter = list.listIterator(); iter.hasNext(); ) { Hunt h = iter.next(); if (h.getTokens().contains("INC")) { for (String tag : h.getTokens().split(";")) { if (tag.contains("INC") && tag.charAt(tag.length() - 1) == 'N') { if (flag) { if (!h.getPropertyA().equals(anotherObject.getPropertyAValue())) { iter.remove(); } } else { if (!h.getPropertyB().equals(anotherObject.getPropertyBValue)) { iter.remove(); } } } } } } }
... It's a list of
List<Instance> listInstances = new ArrayList<Instance>();and the classInstancehasvals = new ArrayList<Boolean>();....
In this case your solution can look like :
public static Instance deleleNthElement(Instance instance, int index) {
instance.getVals().remove(index - 1);
return instance;
}
then with stream you can call the method like so :
int index = 3;
listInstances = listInstances.stream()
.map(instance -> deleleNthElement(instance, index))
.collect(Collectors.toList());
I see no error in your logic, I believe you are missing a ';' from the end of the remove(3).
By the way, List is an Interface, you will need to instanciate as an ArrayList (or some such).
Removed in protest over API pricing and the actions of the admins in the days that followed
If you don't mind, let me bend your requirements a little bit. :-)
One characteristic of the desired result is that the matching elements should end up in one collection, and the non-matching elements should end up in a different collection. In the pre-Java-8 mutative world, the easiest way to think about getting a collection of non-matching elements is to remove the matching elements from the original collection.
But is removal -- modification of the original list -- an intrinsic part of the requirement?
If it isn't, then the result can be achieved via a simple partitioning operation:
Map<Boolean, List<E>> map = data.stream().collect(partitioningBy(predicate));
The result map is essentially two lists, which contain the matching (key = true) and non-matching (key = false) elements.
The advantage is that this technique can be done in one pass and in parallel if necessary. Of course, this creates a duplicate list of non-matching elements compared to removing the matches from the original, but this is the price to pay for immutability. The tradeoffs might be worth it.
I'd keep it simple:
Set<E> removed = set.stream()
.filter(predicate)
.collect(Collectors.toSet());
set.removeAll(removed);
Note that in the first method, you can do the following to simplify removal.
List<Integer> list = new ArrayList<>(List.of(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15));
list.removeIf(element -> element % 3 == 0);
System.out.println(list);
prints:
[1, 2, 4, 5, 7, 8, 10, 11, 13, 14]
Your methods should have some input parameters to represent sequences and return appropriate results instead of just printing them.
- Sequence as
List<Integer>:
remove divisibles by 3;
(optionally) ensure that the first number is 4;
existing sequence not affected, new sequence is created and returned
public static List<Integer> removeDivisiblesBy3(List<Integer> seq) {
return seq.stream()
.dropWhile(x -> x != 4) // optionally ensure to start from 4
.filter(x -> x % 3 != 0) // keep NOT divisible by 3
.collect(Collectors.toList());
}
- Sequence as variable array of
ints:
public static int[] removeDivisiblesBy3(int ... arr) {
return IntStream.of(arr)
.dropWhile(x -> x != 4) // optionally ensure to start from 4
.filter(x -> x % 3 != 0) // keep NOT divisible by 3
.toArray();
}
- Input sequence as
String, output result - the string without spaces
As mentioned in the comments it is enough to useString::replaceAllmethod to remove all unneeded whitespace characters from the input string:
public static String deleteBlanks(String str) {
return str.replaceAll("\\s+", ""); // delete all whitespace characters
}
Tests:
System.out.println(removeDivisiblesBy3(Arrays.asList(1, 4, 6, 7, 9, 11, 12, 19, 22)));
System.out.println(Arrays.toString(removeDivisiblesBy3(1, 4, 6, 7, 9, 11, 12, 19, 22)));
System.out.println(deleteBlanks("Hello world, how are you?"));
Output:
[4, 7, 11, 19, 22]
[4, 7, 11, 19, 22]
Helloworld,howareyou?
I don't think streams win you anything in this case. All you do is iterate over the nested lists and either the enhanced for loop or forEach is more straightforward.
The improvements can come from using removeIf to modify the list and, possibly, from moving the rejection logic out of the loop:
Predicate<ThirdClass> reject = third -> !titles.contains(third.getField());
firstClassList.forEeach(first ->
first.getSecondClassList().forEach(second ->
second.getThirdClassList().removeIf(reject)
)
);
First you can use Stream.map() and Stream.flatMap() to get a Stream containing a List of ThirdClass. To remove the items matching the condition you could use Collection.removeIf(), which removes all items from a collection matching the given condition:
firstClassList.stream() // Stream<FirstClass>
.map(FirstClass::getSecondClassList) // Stream<List<SecondClass>>
.flatMap(Collection::stream) // Stream<SecondClass>
.map(SecondClass::getThirdClassList) // Stream<List<ThirdClass>>
.forEach(thirdList -> thirdList.removeIf(third -> !titles.contains(third.getField())));
This modifies the original List, just like you did in your example. You then can use firstClassList as result for further processing.
Beside that I would recommend using a Set<String> instead of a List<String> for your titles, because it has a time complexity of O(1) instead of O(n):
Set<String> titles = new HashSet<>(Arrays.asList("First Name", "Last Name"));
So you can get access to the nested list inside of a stream operation and then work with that. In this case we can use a nested stream as our predicate for the filter
employees.stream().filter(
employee -> employee.involvedInProjects.stream()
.anyMatch(proj -> proj.projectId == myTargetId ))
This will give you a stream of all of the employees that have at least one project matching you targetId. From here you can operate further on the stream or collect the stream into a list with .collect(Collectors.toList())
If you don't mind modifying the list in place, you can use removeIf and the predicate you will give as parameter will check if the projects where an employee is involved does not match the given id(s).
For instance,
employees.removeIf(e -> e.getInvolvedInProjects().stream().anyMatch(p -> p.getProjectId() == someId));
If the list does not support the removal of elements, grab the stream from the employees list and filter it with the opposite predicate (in this case you could use .noneMatch(p -> p.getProjectId() == someId)) as in removeIf and collect the result using Collectors.toList().