Pass comparator into map with collectors [duplicate] - java-8

Let's say I have a list of Brand objects. The POJO contains a getName() that returns a string. I want to build a
Map<String, Brand>
out of this with the String being the name... but I want the key to be case insensitive.
How do I make this work using Java streams? Trying:
brands.stream().collect(Collectors.groupingBy(brand -> brand.getName().toLowerCase()));
doesn't work, which I think is because I'm not using groupBy correctly.

Collect the results into a case insensitive map
Map<String, Brand> map = brands
.stream()
.collect(
Collectors.toMap(
Brand::getName, // the key
Function.identity(), // the value
(first, second) -> first, // how to handle duplicates
() -> new TreeMap<String, Brand>(String.CASE_INSENSITIVE_ORDER))); // supply the map implementation
Collectors#groupBy won't work here because it returns a Map<KeyType, List<ValueType>>, but you don't want a List as a value, you just want a Brand, from what I've understood.

Related

How to convert a list of objects containing other objects into HashMap

hope you are doing well.
I have some list of other object which again contains two different objects. I have tried couple of ways using Collectors.groupingBy() but didn't get expected output. So help me to figure out solution to this.
Suppose I following three entities:
class FruitFlower {
Fruit fruit;
Flower flower;
}
class Fruit {
String name;
}
class Flower {
String name;
}
And I have a list like this
List<FruitFlower> fruitFlowers = new ArrayList<>();
fruitFlowers.addAll(
new FruitFlower(
new Fruit("Apple"),
new Flower("Rose")
),
new FruitFlower(
new Fruit("Banana"),
new Flower("Lily")
),
new FruitFlower(
new Fruit("Apple"),
new Flower("Sunflower")
),
new FruitFlower(
new Fruit("Banana"),
new Flower("Purple")
),
new FruitFlower(
new Fruit("Banana"),
new Flower("Rose")
)
);
Now, I want to order this list by some filter such that it returns HashMap like this
HashMap<Fruit,List<Flower>> hashMap=new HashMap<>();
Resultant Object:
{
"Apple":["Rose","Sunflower"]
"Banana":["Lily","Purple","Rose"]
}
Where
Expected output is a HadhMap that contains only unique values and a list of other values connected to that particular object. You can consider Objects of String for simplicity.
This is Java question and expected answer should be in Java 8 using stream API.
Thank you in advance.
As you suspected, groupingBy is the right approach.
fruitFlowers.stream().collect(Collectors.groupingBy(
i -> i.fruit,
Collectors.mapping(i -> i.flower, Collectors.toList())
));
The first parameter to groupingBy defines how you want to group them. In this case, we want to group by fruits.
The second parameter describes what the value of the resulting map should be. In this case, we want the values to be the list of flowers.
Note that this approach only works if groupingBy can deduce that two fruits are equivalent. This requires that the Fruit class contains an appropriate implementation of equals and hashCode.
If the Fruit class cannot be extended to add those methods, one can change the first lambda to i -> i.fruit.name, but that would make the resulting Map to have String keys instead of Fruit.

How to find the duplicates values in a Map with in a stream of list?

Say I have this array list:
List<Map<String,String>> fileDataList= new ArrayList<>();
fileDataList.stream().forEach(t->{
//find duplicate map values
});
The list may contain duplicate values like these:
[
{age:12,name:"john"},
{age:11,name:"Mary"},
{age:12,name:"john"}
]
Now,I would like to find the duplicate map values which match both name and age inside the stream without removing them.
I tried with HashSet, But I couldn't understand.
Holger in comments brings a point I missed. If your Map contains only of those name and age properties, you could simply do:
fileDataList.stream()
.distinct()
.collect(Collectors.toList())
And this will be enough. If, on the other hand, you have more properties and
what to filter by only some of them, you could use this utility:
fileDataList.stream()
.filter(distinctByKey(x -> Arrays.asList(x.get("name"), x.get("age")))
.collect(Collectors.toList());
You can transfre your list if Map to list of EntrySet.
List<Map.Entry<String, String>> entries = fileDataList.stream()
.flatMap(e -> e.entrySet().stream())
.collect(toList());

How to convert list of map list<map<string, object>> to list of value of map map<string,list<string>> using steam api java 8

I have a list of map. The map contains string as key & object as value. Most likely values also string. I want to group by one value so that I will get a set of value as key and another group of unique values as a list. Actually, list of map is couchbase select data.
e.g:
[{"id":"1", "status":"pending"},{"id":"2", "status":"download"},{"id":"3", "status":"pending"},{"id":"4", "status":"pending"}, {"id":"5", "status":"ready"},{"id":"6", "status":"download"}] => {"pending":["1","3","4"], "download":["2","6"], "ready":["5"]}
Try this out. Notice that my values are Strings NOT Objects as yours. In your case you need to cast it explicitly to String like so,
s -> (String) s.get("status")
s -> (String) s.get("id")
Map<String, List<String>> idsByStatus = listOfMap.stream().collect(
Collectors.groupingBy(s -> s.get("status"), Collectors.mapping(s -> s.get("id"), Collectors.toList())));

java8 stream - filter map and aggregate

Lets say I have a list of rooms
List<Room> rooms;
And each room has a list of persons.
Using java8 streams I want to iterate the list of rooms, get all persons, execute some method on each node (doSomething()) and get a list of all the filtered objects.
Is this the best practive using java 8?
List<Asset> pesonsList= new ArrayList<>();
for (Room room : rooms)
room.getPersonsList().stream()
.filter(person -> person.isTall())
.forEach(person -> {
doSomething(person);
pesonsList.add(person);
});
You'd probably better do it like this:
List<Person> persons =
rooms.stream()
.flatMap(room -> room.getPersonsList().stream())
.filter(Person::isTall)
.peek(this::doSomething)
.collect(Collectors.toList());
In addition to the #JBNizet answer I'd suggest to replace getPersonsList() in Room class with persons() method: instead of
List<Person> getPersonsList() {...}
Create this method:
Stream<Person> persons() {...}
The first advantage is that streaming operations will become shorter:
List<Person> persons = rooms.stream()
.flatMap(Room::persons)
.filter(Person::isTall)
.peek(this::doSomething)
.collect(Collectors.toList());
The second advantage is that it might be more implementation independent, thus more efficient. Suppose that internally you store persons in the Set or in array. When having getPersonsList() method you will need to copy all the persons to the new list first. When having persons() method, you can easily create a stream directly from your internal data structure whatever it is. I believe, it's Java 8 way to return the stream of internal objects instead of some specific data structure were it List or array or whatever.

Spark - sort by value with a JavaPairRDD

Working with apache spark using Java. I got an JavaPairRDD<String,Long> and I want to sort this dataset by its value. However, it seems that there only is sortByKey method in it. How could I sort it by the value of Long type?
dataset.mapToPair(x -> x.swap()).sortByKey(false).mapToPair(x -> x.swap()).take(100)
'Secondary sort' is not supported by Spark yet (See SPARK-3655 for details).
As a workaround, you can sort by value by swaping key <-> value and sorting by key as usual.
In Scala would be something like:
val kv:RDD[String, Long] = ???
// swap key and value
val vk = kv.map(_.swap)
val vkSorted = vk.sortByKey
I did this using a List, which now has a sort(Comparator c) method
List<Tuple2<String,Long>> touples = new ArrayList<>();
touples.addAll(myRdd.collect()); //
touples.sort((Tuple2<String, Long> o1, Tuple2<String, Long> o2) -> o2._2.compareTo(o1._2));
It is longer than #Atul solution and i dont know if performance wise is better, on an RDD with 500 items shows no difference, i wonder how does it work with a million records RDD.
You can also use Collections.sort and pass in the list provided by the collect and the lambda based Comparator

Resources