I have a list of names and a list of versions. I want to get all permutations which are constructed by concatenating the string from two lists. I am using two for loop to do this but I want to switch to a more functional style approach. Here is my solution:
List<String> names = new ArrayList<>();
List<String> versions = new ArrayList<>();
List<String> result = new ArrayList<>();
names.forEach(name -> versions.stream().map(version -> result.add(name.concat(version))));
Is there a better way to do it?
You are looking for the "Cartesian Product" of names and versions — basically the return set/list from the aforementioned sets/lists.
final Stream<List<String>> result = names.stream()
.flatMap(s1 -> versions.stream().flatMap(s2 -> Stream.of(Arrays.asList(s1, s2))));
result.forEach(System.out::println);
Keep in mind that operation is super expensive. Google's Guava have this implemented also under com.google.common.collect.Sets.cartesianProduct(s1, s2).
You should look forward to use flatMap while streaming over names and then performing map operation further correctly as:
List<String> result = names.stream() // for each name
.flatMap(name -> versions.stream() // for each version
.map(version -> name.concat(version))) // concat version to the name
.collect(Collectors.toList()); // collect all such names
Or a bit tidier:
final List<String> result = names.stream() // Stream the Names...
.flatMap(name -> versions.stream() // ...together with Versions.
.map (version -> name.concat(version))) // Combine Name+Version
.collect(Collectors.toList()); // & collect in List.
I have 2 arrays and want to make a list of role.getRoleName() only with elements that are in both arrays using streams.
final List<String> roleNames = new ArrayList<>();
roleNames = Arrays.stream(roles).filter(role -> role.getRoleId()
== Arrays.stream(permissions).map(permission -> permission.getRoleId()));
when I write the above code I get
Operator '==' cannot be applied to 'int', 'java.util.stream.Stream'
I understand the error, but I don't know the solution of how to make the permissions stream in only permission.getRoleId integers.
There is no way to compare such incompatible types as int and Stream.
Judging from what you've shown, Stream#anyMatch might a good candidate.
roleNames = Arrays.stream(roles)
.map(Role::getRoleId)
.filter(id -> Arrays.stream(permissions).map(Role::getRoleId).anyMatch(p -> p.equals(id)))
.collect(Collectors.toList());
This part Arrays.stream(permissions).map(Role::getRoleId) may be pre-calculated and stored into a Set.
final Set<Integer> set = Arrays.stream(permissions)
.map(Role::getRoleId)
.collect(Collectors.toSet());
roleNames = Arrays.stream(roles)
.filter(role -> set.contains(role.getRoleId()))
.map(Role::getRoleName)
.collect(Collectors.toList());
What you can do is collect unique roleIds for the array of Permissions into a Set as a computed result and perform a contains check as you iterate through the array of Roles. This could be done as :
final Set<Integer> uniqueRoleForPermissions = Arrays.stream(permissions)
.map(Permission::getRoleId)
.collect(Collectors.toSet());
final List<String> roleNames = Arrays.stream(roles)
.filter(role -> uniqueRoleForPermissions.contains(role.getRoleId()))
.map(Role::getRoleName)
.collect(Collectors.toList());
In previous question I asked previously Which FunctionalInterface should I use?
Now I was trying to add to List<Integer> and not just two Integers a and b, such that each index adds to the same index of another list.
I had previously
BinaryOperator<Integer> binaryOperator = Integer::sum;
for adding two integers using binaryOperator.apply(int a,int b). Is there a similar way like
BinaryOperator<List<Integer>> binaryOperator = List<Integer>::sum;
and then get the result in List<Integer> cList?
if you want to perform some computation on the elements at corresponding indices (in this specific case the summation) there's no need to use a BinaryOperator, instead use IntStream.range to generate the indices:
// generates numbers from 0 until list.size exclusive
IntStream.range(0, list.size())....
// generates numbers from 0 until the minimum of the two lists exclusive if needed
IntStream.range(0, Math.min(list.size(), list2.size()))....
The common name for this type of logic is "zip"; i.e. when given two input sequences it produces an output sequence in which every two elements from the input sequences at the same position are combined using some function.
There's no built-in method in the standard library for this, but you can find some generic implementations here.
for example, using the zip method in the accepted answer of the linked post, you could simply do:
List<Integer> result = zip(f.stream(), s.stream(), (l, r) -> l + r).collect(toList());
or using method reference:
List<Integer> result = zip(f.stream(), s.stream(), Math::addExact).collect(toList());
where f and s are your list of integers.
You can use IntStream.range() to iterate over elements, then mapToObj() to map them to their sum and the collect() them in the third list.
Given that your lists are of same size
List<Integer> first = List.of(); // initialised
List<Integer> second = List.of(); // initialised
you can get the third list as :
List<Integer> third = IntStream.range(0, first.size())
.mapToObj(i -> first.get(i) + second.get(i))
.collect(Collectors.toList());
In terms of BinaryOperator, you can represent it as :
BinaryOperator<List<Integer>> listBinaryOperator = (a, b) -> IntStream.range(0, first.size())
.mapToObj(i -> first.get(i) + second.get(i))
// OR from your existing code
// .mapToObj(i -> binaryOperator.apply(first.get(i), second.get(i)))
.collect(Collectors.toList());
Or you can make it more readable by abstracting out the logic into a method and using it as :
BinaryOperator<List<Integer>> listBinaryOperator = YourClass::sumOfList;
where sumOfList is defined as :
private List<Integer> sumOfList(List<Integer> first, List<Integer> second) {
return IntStream.range(0, first.size())
.mapToObj(i -> first.get(i) + second.get(i))
.collect(Collectors.toList());
}
What you can do is define your own utility method whose single task is zipping the two input lists :
<T> List<T> zip(final List<? extends T> first, final List<? extends T> second, final BinaryOperator<T> operation)
{
return IntStream.range(0, Math.min(first.size(), second.size()))
.mapToObj(index -> operation.apply(first.get(index), second.get(index)))
.collect(Collectors.toList());
}
This way, you can sum your two input lists as :
zip(first, second, Integer::sum)
Suppose I have an object containing a collection, each elements on the said collection contains a collection, and each collection contains a collection.
And I want to iterate on the deepest objects and apply the same code to it.
The imperative way is trivial, but is there a way to lambda-fy this all?
Here is how the code looks today:
My object o;
SecretType computedThingy = 78;
for (FirstLevelOfCollection coll : o.getList()) {
for (SecondLevelOfCollection colColl : coll.getSet()) {
for (MyCoolTinyObjects mcto : colColl.getFoo()) {
mcto.setSecretValue(computedThingy);
}
}
}
I can see how to make a lambda out of the deepest loop:
colColl.getFoo().stream().forEach(x -> x.setSecretValue(computedThingy)
But can I do more?
flatMap is available for such a purpose. What you get here is iteration over all elements of the various deepest collections as if they were a single collection:
o.getList().stream()
.flatMap(c1 -> c1.getSet().stream())
.flatMap(c2 -> c2.getFoo().stream())
.forEach(x -> x.setSecretValue(computedThingy));
flatMap to the rescue, simple example with a nested collection of String
See also:
Java 8 Streams FlatMap method example
Turn a List of Lists into a List Using Lambdas
Set<List<List<String>>> outerMostSet = new HashSet<>();
List<List<String>> middleList = new ArrayList<>();
List<String> innerMostList = new ArrayList<>();
innerMostList.add("foo");
innerMostList.add("bar");
middleList.add(innerMostList);
List<String> anotherInnerMostList = new ArrayList<>();
anotherInnerMostList.add("another foo");
middleList.add(anotherInnerMostList);
outerMostSet.add(middleList);
outerMostSet.stream()
.flatMap(mid -> mid.stream())
.flatMap(inner -> inner.stream())
.forEach(System.out::println);
Produces
foo
bar
another foo
Given a list of elements, I want to get the element with a given property and remove it from the list. The best solution I found is:
ProducerDTO p = producersProcedureActive
.stream()
.filter(producer -> producer.getPod().equals(pod))
.findFirst()
.get();
producersProcedureActive.remove(p);
Is it possible to combine get and remove in a lambda expression?
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.
Consider using vanilla java iterators to perform the task:
public static <T> T findAndRemoveFirst(Iterable<? extends T> collection, Predicate<? super T> test) {
T value = null;
for (Iterator<? extends T> it = collection.iterator(); it.hasNext();)
if (test.test(value = it.next())) {
it.remove();
return value;
}
return null;
}
Advantages:
It is plain and obvious.
It traverses only once and only up to the matching element.
You can do it on any Iterable even without stream() support (at least those implementing remove() on their iterator).
Disadvantages:
You cannot do it in place as a single expression (auxiliary method or variable required)
As for the
Is it possible to combine get and remove in a lambda expression?
other answers clearly show that it is possible, but you should be aware of
Search and removal may traverse the list twice
ConcurrentModificationException may be thrown when removing element from the list being iterated
The direct solution would be to invoke ifPresent(consumer) on the Optional returned by findFirst(). This consumer will be invoked when the optional is not empty. The benefit also is that it won't throw an exception if the find operation returned an empty optional, like your current code would do; instead, nothing will happen.
If you want to return the removed value, you can map the Optional to the result of calling remove:
producersProcedureActive.stream()
.filter(producer -> producer.getPod().equals(pod))
.findFirst()
.map(p -> {
producersProcedureActive.remove(p);
return p;
});
But note that the remove(Object) operation will again traverse the list to find the element to remove. If you have a list with random access, like an ArrayList, it would be better to make a Stream over the indexes of the list and find the first index matching the predicate:
IntStream.range(0, producersProcedureActive.size())
.filter(i -> producersProcedureActive.get(i).getPod().equals(pod))
.boxed()
.findFirst()
.map(i -> producersProcedureActive.remove((int) i));
With this solution, the remove(int) operation operates directly on the index.
Use can use filter of Java 8, and create another list if you don't want to change the old list:
List<ProducerDTO> result = producersProcedureActive
.stream()
.filter(producer -> producer.getPod().equals(pod))
.collect(Collectors.toList());
I'm sure this will be an unpopular answer, but it works...
ProducerDTO[] p = new ProducerDTO[1];
producersProcedureActive
.stream()
.filter(producer -> producer.getPod().equals(pod))
.findFirst()
.ifPresent(producer -> {producersProcedureActive.remove(producer); p[0] = producer;}
p[0] will either hold the found element or be null.
The "trick" here is circumventing the "effectively final" problem by using an array reference that is effectively final, but setting its first element.
With Eclipse Collections you can use detectIndex along with remove(int) on any java.util.List.
List<Integer> integers = Lists.mutable.with(1, 2, 3, 4, 5);
int index = Iterate.detectIndex(integers, i -> i > 2);
if (index > -1) {
integers.remove(index);
}
Assert.assertEquals(Lists.mutable.with(1, 2, 4, 5), integers);
If you use the MutableList type from Eclipse Collections, you can call the detectIndex method directly on the list.
MutableList<Integer> integers = Lists.mutable.with(1, 2, 3, 4, 5);
int index = integers.detectIndex(i -> i > 2);
if (index > -1) {
integers.remove(index);
}
Assert.assertEquals(Lists.mutable.with(1, 2, 4, 5), integers);
Note: I am a committer for Eclipse Collections
The below logic is the solution without modifying the original list
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");
List<String> str3 = str1.stream()
.filter(item -> !str2.contains(item))
.collect(Collectors.toList());
str1 // ["A", "B", "C", "D"]
str2 // ["D", "E"]
str3 // ["A", "B", "C"]
When we want to get multiple elements from a List into a new list (filter using a predicate) and remove them from the existing list, I could not find a proper answer anywhere.
Here is how we can do it using Java Streaming API partitioning.
Map<Boolean, List<ProducerDTO>> classifiedElements = producersProcedureActive
.stream()
.collect(Collectors.partitioningBy(producer -> producer.getPod().equals(pod)));
// get two new lists
List<ProducerDTO> matching = classifiedElements.get(true);
List<ProducerDTO> nonMatching = classifiedElements.get(false);
// OR get non-matching elements to the existing list
producersProcedureActive = classifiedElements.get(false);
This way you effectively remove the filtered elements from the original list and add them to a new list.
Refer the 5.2. Collectors.partitioningBy section of this article.
As others have suggested, this might be a use case for loops and iterables. In my opinion, this is the simplest approach. If you want to modify the list in-place, it cannot be considered "real" functional programming anyway. But you could use Collectors.partitioningBy() in order to get a new list with elements which satisfy your condition, and a new list of those which don't. Of course with this approach, if you have multiple elements satisfying the condition, all of those will be in that list and not only the first.
the task is: get ✶and✶ remove element from list
p.stream().collect( Collectors.collectingAndThen( Collector.of(
ArrayDeque::new,
(a, producer) -> {
if( producer.getPod().equals( pod ) )
a.addLast( producer );
},
(a1, a2) -> {
return( a1 );
},
rslt -> rslt.pollFirst()
),
(e) -> {
if( e != null )
p.remove( e ); // remove
return( e ); // get
} ) );
resumoRemessaPorInstrucoes.removeIf(item ->
item.getTipoOcorrenciaRegistro() == TipoOcorrenciaRegistroRemessa.PEDIDO_PROTESTO.getNome() ||
item.getTipoOcorrenciaRegistro() == TipoOcorrenciaRegistroRemessa.SUSTAR_PROTESTO_BAIXAR_TITULO.getNome());
Combining my initial idea and your answers I reached what seems to be the solution
to my own question:
public ProducerDTO findAndRemove(String pod) {
ProducerDTO p = null;
try {
p = IntStream.range(0, producersProcedureActive.size())
.filter(i -> producersProcedureActive.get(i).getPod().equals(pod))
.boxed()
.findFirst()
.map(i -> producersProcedureActive.remove((int)i))
.get();
logger.debug(p);
} catch (NoSuchElementException e) {
logger.error("No producer found with POD [" + pod + "]");
}
return p;
}
It lets remove the object using remove(int) that do not traverse again the
list (as suggested by #Tunaki) and it lets return the removed object to
the function caller.
I read your answers that suggest me to choose safe methods like ifPresent instead of get but I do not find a way to use them in this scenario.
Are there any important drawback in this kind of solution?
Edit following #Holger advice
This should be the function I needed
public ProducerDTO findAndRemove(String pod) {
return IntStream.range(0, producersProcedureActive.size())
.filter(i -> producersProcedureActive.get(i).getPod().equals(pod))
.boxed()
.findFirst()
.map(i -> producersProcedureActive.remove((int)i))
.orElseGet(() -> {
logger.error("No producer found with POD [" + pod + "]");
return null;
});
}
A variation of the above:
import static java.util.function.Predicate.not;
final Optional<MyItem> myItem = originalCollection.stream().filter(myPredicate(someInfo)).findFirst();
final List<MyItem> myOtherItems = originalCollection.stream().filter(not(myPredicate(someInfo))).toList();
private Predicate<MyItem> myPredicate(Object someInfo) {
return myItem -> myItem.someField() == someInfo;
}