how to collect to LinkedHashMap in java 8 [duplicate] - java

This question already has answers here:
Transform a List<Object> to a Map<String, Integer> such that the String is not a duplicate value using Java 8 Streams
(4 answers)
Closed 2 years ago.
Currently we are converting list returned by repository.findAll() into the Map by doing:
Map<Long, FooDto> fooMap=fooRepository.findAll()
.stream()
.map(fooDomainToDtoMapper::mapDomainToDto)
.collect(Collectors.toMap(fooDto::getfooId, foo -> foo));
But we want to preserve the order returned by the repository.findAll(). We want to return the records in the descending order and then collect it to the LinkedHashmap by doing something like :
Map<Long, FooDto> fooMap= fooRepository.findAll(Sort.by(Sort.Direction.DESC, "name"))
.stream()
.map(fooDomainToDtoMapper::mapDomainToDto)
//trying to do something like:
.collect(Collectors.toMap(fooDto::getfooId, foo -> foo,LinkedHashMap::new));
If we try to collect the above descending order result in the normal Collectors.toMap then sorted query has no effect at all, it is looking like normal select in the final result.

If you want to pass a supplier for the Map, you must pass a merge function too:
Map<Long, FooDto> fooRepository.findAll(Sort.by(Sort.Direction.DESC, "name"))
.stream()
.map(fooDomainToDtoMapper::mapDomainToDto)
.collect(Collectors.toMap(fooDto::getfooId,
Function.identity(),
(v1,v2)->v1,
LinkedHashMap::new));

Try this:
.stream()
.map(fooDomainToDtoMapper::mapDomainToDto)
.collect(LinkedHashMap::new,
(map, fooDto) -> map.put(fooDto.getfooId(), fooDto),
Map::putAll);

Related

Store multiple values for a key in Collectors.toMap() in Java [duplicate]

This question already has answers here:
Java stream/collect: map one item with multiple fields to multiple keys
(1 answer)
HashMap with multiple values under the same key
(21 answers)
Closed 1 year ago.
This is how my map looks like.
Map<String, String> maps = List.stream().collect(Collectors.toMap(Cat::getName, Cat::getNumber, (c1,c2) -> c1));
If I already have "Lucy, 101" in maps then I am unable to add another value corresponding to the name Lucy i.e "Lucy, 102". Is there any way to change the merge function [ (c1,c2) -> c1 ] so that I can have two values corresponding to a single key (Lucy) in my maps?
By your requirement, in order to allow multiple values for the same key, you need to implement the result as Map<String, Collection<String>>.
In your case, you can merely use groupingBy + mapping collectors instead of toMap with the merge function:
Map<String, List<String>> maps = List.stream()
.collect(Collectors.groupingBy(
Cat::getName,
Collectors.mapping(Cat::getNumber, Collectors.toList())
);
However, you may want to consider a merge function as joining strings:
Map<String, String> maps = List.stream()
.collect(Collectors.toMap(
Cat::getName,
Cat::getNumber, (num1, num2) -> String.join("; ", num1, num2)
);
Then the map would contain "compound" values in the form of a string.
Since the type of your map is Map<String, String>, it can only return one string. However, you expect to get multiple strings from get. You need to change the type of the map to e.g. Map<String, List<String>> or Map<String, Collection<String>>.
Then, you can use groupingBy like this:
Map<String, List<String>> map = yourList.stream().collect(Collectors.groupingBy(
Cat::getName, // group by the name
Collectors.mapping( // map each group of cats to their numbers
Cat::getNumber, Collectors.toList() // collect each group to a list
)
));
If you are okay with multiple numbers in the same string (e.g. "101 102"), you can use Collectors.joining:
Map<String, String> map = yourList.stream().collect(Collectors.groupingBy(
Cat::getName,
Collectors.mapping(
Cat::getNumber, Collectors.joining(" ")
)
));

Java 8 Stream sort map of string to list<String> based on list<String> [duplicate]

This question already has answers here:
Sort a Map<Key, Value> by values
(64 answers)
Closed 3 years ago.
I have a map with key as string and value as list of strings
I want to sort the map based on the list of strings(Lexicographically).
If I have a List<List<String>> then I can sort by
List<List<String>> sortedlist = new LinkedList<>();
sortedlist.sort((l1, l2) -> l1.get(0).compareTo(l2.get(0)));
But I have a Map<String, List<String>> sortedMap and I want to sort this based on the values, i.e. first element of each list within the value set of the map.
I am trying to form a stream lambda expression something like this.
HashMap<String, List<String> > sortedmap = new HashMap<>();
sortedmap = map.values().stream().sorted(Map.Entry.comparingByValue((l1, l2) -> l1.get(0).compareTo(l2.get(0))) )
But it is not a valid lambda expression.
How do I do this with Java 8 streams?
Try this:
Map<String, List<String>> sortedMap =
map.entrySet()
.stream()
.sorted(Map.Entry.comparingByValue(Comparator.comparing(l -> l.get(0))))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (v1, v2) -> v1, LinkedHashMap::new));
Note that sorting would not make any sense while collecting into a HashMap, since it's unordered.

Java 8 - How to search a MultiValueMap with value? [duplicate]

This question already has answers here:
Create only 1 list from a map where map value is list using JAVA 8 Streams
(3 answers)
Closed 4 years ago.
I have a
MultiValueMap<String, String> map = new LinkedMultiValueMap<>();
The type of value is a list of strings:
List<String> valueList = map.get('key');
How can i search through this map (through all the valueLists within this map) and get all the values which startsWith 'xy' in a list back?
I hope the question is clear.
I have tried this, but no success:
map
.entrySet()
.stream()
.filter(e-> e.getValue().stream().filter(value -> value.startsWith(searchString)))
.collect(Collectors.toList());
I get this error: Stream cannot be converted to boolean
If I understood your problem correctly:
map.values()
.stream()
.flatMap(List::stream)
.filter(x -> x.startsWith(searchString))
.collect(Collectors.toList())

Java 8 Map not being sorted by value properly [duplicate]

This question already has answers here:
Java 8 is not maintaining the order while grouping
(2 answers)
Stream doesn't preserve the order after grouping
(3 answers)
Closed 4 years ago.
I've read many questions regarding Java 8 and Collections on this site and, given my limited understanding of java streams, I'm having some trouble trying to sort this Map.
My code is as follows, being tradeList an ArrayList();
Map<String, Double> buyReport = tradeList.stream().filter(trade -> trade.getInstruction() == Instruction.BUY)
.sorted(Comparator.comparing(trade -> trade.getInstructionDate()))
.collect(Collectors.groupingBy(trade -> dateFormat.format(trade.getInstructionDate()),
Collectors.summingDouble(trade -> trade.getUSDAmount())));
Does it make any sense to include the .sorted() statement when composing a HashMap? I tried to create a LinkedHashmap, use a custom comparator for the value i need the object instances to compare (a Double), but to no avail.
I can include any other piece of code you may find useful.
Thanks in advance!!
Update: tried this recently; still getting results unordered when grouping by company code and then summing company totals:
Map<String, Double> entityOutgoingReport = tradeList.stream()
.filter(trade -> trade.getInstruction() == Instruction.SELL)
.collect(Collectors.groupingBy(trade -> String.valueOf(trade.getEntity()),
LinkedHashMap::new,
Collectors.summingDouble(trade -> trade.getUSDAmount())));
for (String entity : entityOutgoingReport.keySet()) {
String key = entity;
String value = decFormat.format(entityOutgoingReport.get(entity));
tableBuilder.addRow(key, value); //Just pretty printing to console
}
Simply supply a LinkedHashMap into which the results will be inserted therefore maintaining order.
.collect(Collectors.groupingBy(trade ->
dateFormat.format(trade.getInstructionDate()),
LinkedHashMap::new,
Collectors.summingDouble(trade -> trade.getUSDAmount())));
Full code:
Map<String, Double> entityOutgoingReport =
tradeList.stream()
.filter(trade -> trade.getInstruction() == Instruction.SELL)
.sorted(Comparator.comparing(trade -> trade.getInstructionDate()))
.collect(Collectors.groupingBy(trade -> String.valueOf(trade.getEntity()),
LinkedHashMap::new,
Collectors.summingDouble(trade -> trade.getUSDAmount())));

How to add values from Map<T,List<L>> map to List<L>? [duplicate]

This question already has answers here:
Convert List of List into list in java
(5 answers)
Closed 5 years ago.
I have a multimap Map<T,List<L>> map and I need a list with all the values of the values from the map, namely List<L>. With map.values() I get a List<List<L>>, but thats not what I want.
Does someone know a clean solution without looping?
If you are using Java 8, you could collect all L values from all List<L>s in a single List<L> by Stream#flatMap:
final List<L> list = map
// get a Collection<List<L>>
.values()
// make a stream from the collection
.stream()
// turn each List<L> into a Stream<L> and merge these streams
.flatMap(List::stream)
// accumulate the result into a List
.collect(Collectors.toList());
Otherwise, a for-each approach with Collection#addAll can be applied:
final List<L> list = new ArrayList<>();
for (final List<L> values : map.values()) {
list.addAll(values);
}

Categories