This question already has answers here:
How to Convert List<String> to List<Object>
(7 answers)
Closed last year.
I have a Collection of Strings which I want to iterate and do a DB query on each of them and collect the response of each query into a Collection of Objects. I am sure we can do this through a for loop iterator but is there a way to do it with Java8 Streams ? This is what I came up with -
static Collection<Action> getActions(Collection<String> actionIds, RequestContext rc) {
List<Collection<Action>> ac = actionIds.stream().map(str -> hashmap.get(str)).collect(Collectors.toList());
return ac.get(0);
}
Action is a custom class. I read that I may need to do something like this - https://itsallbinary.com/java-8-create-custom-streams-collector/ .
Is this necessary ? Or any easier ways ?
If I use this .collect(toCollection(ArrayList::new)), it gives me Collection<Collection<Action>>
It seems that hashmap is a Map<String, Collection<Action>> which can be converted into filtered Collection<Action> using Stream::flatMap, as suggested in the comments.
Possibly it's worth to filter available actionIds as a defensive measure. Also, some specific implementation of the collection needs to be selected or at least Set or List depending on the actual requirements (e.g. if the order of the actions needs to be maintained, or if the duplicate actions need to be filtered, etc.)
Most likely, a mere Collectors::toList would be fine for the result:
static Collection<Action> getActions(Collection<String> actionIds, RequestContext rc) {
return actionIds.stream()
.filter(hashmap::containsKey) // make sure nulls not returned
.map(hashmap::get) // Stream<Collection<Action>>
.flatMap(Collection::stream) // Stream<Action>
.collect(Collectors.toList()); // List<Action>
}
"Unique" values may be retrieved using Stream::distinct before collecting to list or by collecting to a set instead of list (using LinkedHashSet to maintain the order of insertion):
static Collection<Action> getDistinctActions(Collection<String> actionIds, RequestContext rc) {
return actionIds.stream()
.filter(hashmap::containsKey) // make sure nulls not returned
.flatMap(actions -> actions.stream()) // Stream<Action>
.collect(Collectors.toCollection(LinkedHashSet::new));
}
Related
I would like to remove a String entry and an empty String from the Array of Strings.
My array of String contains the following values from index 0 to 3 - 'Name','First','Last', ""
Here is what I tried, using the stream API and Java 11 Predicate.not API:
Arrays.asList(myStringArray).stream()
.filter(Predicate.not(String::isEmpty).or(entry -> entry.equals("Name")))
.collect(Collectors.toList());
I would expect the entries "Name" and "" to be removed from myStringArray, what am I missing?
Another possibility:
var newList = new ArrayList<>(Arrays.asList(myStringArray));
newList.removeAll(List.of("", "Name"));
Or, if you know that "Name" is always the first entry and "" is always the last entry, you could do this, which has better performance as it doesn't take any copies of anything:
var newList = Arrays.asList(myStringArray).subList(1, myStringArray.length - 1)
My question formation may have been poor, sorry about that and here's what I was looking for and it produces the desired result that I need -
Arrays.asList(myStringArray).stream()
.filter(Predicate.not(String::isEmpty))
.filter(Predicate.not(entry -> entry.equals("Name")))
.collect(Collectors.toList());
Another way to do this without doing two filter calls can be:
Arrays.asList(myStringArray).stream()
.filter(Predicate.not(String::isEmpty).and(entry -> !entry.equals("Name")))
.collect(Collectors.toList())
I think the problem you have, is that you are not taking resulting list. The thing is, the items are not removed from the array, but new list is created with items without removed items.
so just do:
var newList = Arrays.asList(myStringArray).stream()
.filter(Predicate.not(String::isEmpty)).filter(Predicate.not(entry -> entry.equals("Name")))
.collect(Collectors.toList());```
Currently, that's my code:
Iterable<Practitioner> referencedPractitioners = this.practitionerRepository.findAllById(
Optional.ofNullable(patient.getPractitioners())
.map(List::stream)
.orElse(Stream.of())
.map(Reference::getIdPart)
.collect(Collectors.toList())
);
As you can see, I'm using this.practitionerRepository.findAllById(Iterable<String> ids), in order to get all using a single communication with database.
I was trying to change it using this:
Optional.ofNullable(patient)
.map(org.hl7.fhir.r4.model.Patient::getPractitioners)
.map(List::stream)
.orElse(Stream.of())
.map(Reference::getIdPart)
.collect(????????);
How could I use this.practitionerRepository.findAllById(Iterable<String> ids) into a custom collector in collect method?
Remember I need to get all entities at once. I can't get them one by one.
You can use Collectors.collectingAndThen(Collector<T,A,R> downstream, Function<R,RR> finisher) specialized collector for that.
Make a list of IDs using the Collector.toList() collector and then
Pass a reference practitionerRepository::findAllById to convert from List<String> to Iterable<Practitioner>
Example:
Iterable<Practitioner> referencedPractitioners = Optional.ofNullable(patient)
.map(Patient::getPractitioners)
.map(List::stream)
.orElseGet(Stream::of)
.map(Reference::getIdPart)
.collect(Collectors.collectingAndThen(toList(), practitionerRepository::findAllById));
I have the following POJO:
public class Order {
private String name;
private String status;
private BigDecimal total;
// getters, setters and ctors down here
}
I am looping through a List<Order> and trying to update all their status fields to a value of "ORDERED". The old (pre Streaming API) way of doing this was:
for (Order order : orders) {
order.setStatus("ORDERED");
}
I'm trying to figure out the Java 8 ("Streaming") way of accomplishing the same thing. My best attempt thus far:
orders.stream().map(order -> order.setStatus("H"));
Produces a compiler error:
"Incompatible types. Required List but 'map' was inferred to Stream: no instance(s) of type variable(s) R exist so that Stream conforms to List"
Any ideas where I'm going awry?
Use forEach:
orders.forEach(order -> order.setStatus("H"));
You do not want to use Stream.map() because it requires a return value which replaces the original value in the stream. You are also missing a terminal operation in your stream, so even if you fix that by returning the original value it wont work. Stream.forEach() is a terminal operation you can use for this.
To update each object in your list you can just use orders.forEach(). This is the same as orders.stream().forEach().
orders.forEach(o -> o.setStatus("H"));
If you want to update only some values of your List you can use Stream.filter() before:
orders.stream()
.filter(o -> "ABC".equals(o.getName())
.forEach(o -> o.setStatus("H"));
I have a collection of objects, with the following type:
{
String action_name; //add or delete
long action_time;
String action_target;
}
Need to get the latest merged operation on each action_target
Sample input data:
[add|1001|item1, add|1002|item2, delete|1003|item1, add|1004|item1]
Expected result:
[add|1002|item2, add|1004|item1]
Sample input data:
[add|1001|item1, add|1002|item2, delete|1003|item1]
Expected result:
[add|1002|item2]
Sample input data:
[delete|1001|item1, add|1002|item2, add|1003|item1]
Expected result:
[add|1002|item2, add|1003|item1]
Is this approachable using Java8 stream APIs? Thanks.
You want to group by one criteria (the action_target) combined with reducing the groups to the maximum of their action_time values:
Map<String,Item> map=items.stream().collect(
Collectors.groupingBy(item->item.action_target,
Collectors.collectingAndThen(
Collectors.maxBy(Comparator.comparing(item->item.action_time)),
Optional::get)));
This returns a Map<String,Item> but, of course, you may call values() on it to get a collection of items.
Beautified with static imports, the code looks like:
Map<String,Item> map=items.stream().collect(groupingBy(item->item.action_target,
collectingAndThen(maxBy(comparing(item->item.action_time)), Optional::get)));
Your additional request of taking care of idempotent "add" and follow-up "delete" actions can be simplified to “remove items whose last action is "delete"” which can be implemented just by doing that after collecting using a mutable map:
HashMap<String,Item> map=items.stream().collect(groupingBy(
item->item.action_target, HashMap::new,
collectingAndThen(maxBy(comparing(item->item.action_time)), Optional::get)));
map.values().removeIf(item->item.action_name.equals("delete"));
In WEKA-a data mining software for the MICROARRAY DATA, how can i remove the redundant tuples from the existing data set? The code to remove the redundancy should be in JAVA.
i.e, the data set contains data such as
H,A,X,1,3,1,1,1,1,1,0,0,0
D,R,O,1,3,1,1,2,1,1,0,0,0
H,A,X,1,3,1,1,1,1,1,0,0,0
C,S,O,1,3,1,1,2,1,1,0,0,0
H,A,X,1,3,1,1,1,1,1,0,0,0
here the tuples 1,4,5 are redundant.
The code should return the following REDUNDANCY REMOVED data set...
H,A,X,1,3,1,1,1,1,1,0,0,0
D,R,O,1,3,1,1,2,1,1,0,0,0
C,S,O,1,3,1,1,2,1,1,0,0,0
You could use one of the classes that implements the Set such as java.util.HashSet.
You can load your data set into the Set and then extract them either by converting to an array via the Set.toArray() method or by iterating over the set.
Set<Tuple> tupleSet = new HashSet<Tuple>();
for (Tuple tuple: tupleList) {
tupleSet.add(tuple);
}
// now all of your tuples are unique
for (Tuple tuple: tupleSet) {
System.out.println("tuple: " + tuple);
}