my people object looks like this
class People {
this.name,
this.height,
this.age
}
I have a list from a database query like so
List<People> people = DAO.queryAllPeople();
which returns 100's of people
Then I want just people with unique height
Set<People> uniquePeople = list
.stream()
.map(people -> people)
.filter(Objects::nonNull)
.collect( Collectors.toSet() );
But this is returning all objects, is there a way to get people distinct by height?
Edit this is what I want but I want the Person object so I can call get methods when I loop over it
Set<String> people = people
.stream()
.map(People::getHeight)
.filter(Objects::nonNull)
.collect( Collectors.toSet() );
First, naming a class People
is not natural, a better name would be Person
.
As, for solving your problem, you can override equals
and hashcode
for height
only like this:
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
return height == person.height;
}
@Override
public int hashCode() {
return height;
}
The above assumes height is an int
field. if instead, it's Integer
, then you'll need to implement it like so:
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
return height != null ? height.equals(person.height) : person1.height == null;
}
@Override
public int hashCode() {
return height != null ? height.hashCode() : 0;
}
Now, you can do:
Set<People> uniquePeople =
myList.stream()
.filter(Objects::nonNull)
.collect(Collectors.toSet());
or for what ever reason you don't want to override equals
and hashcode
you can do it with the toMap
collector .
Set<Person> values = new HashSet<>(myList.stream()
.collect(Collectors.toMap(Person::getHeight, Function.identity(),
(left, right) -> left))
.values());
deciphering the above code snippet:
myList.stream()
.collect(Collectors.toMap(Person::getHeight, Function.identity(),
(left, right) -> left))
.values()
This creates a stream from myList
collecting it to a map implementation, where Person::getHeight
is a function extracting the person height for the map keys, Function.identity()
is a function extracting a person object for the map values, (left, right) -> left)
is known as the merge function meaning if two given people have the same key (height) we return the first person ( left
). Conversely, (left, right) -> right
will return the last person in the case of key conflict.
Lastly, we pass the result of this processing to the HashSet
constructor to create a Set<Person>
.
Split this task into two subtasks.
First group people by height:
Map<Integer, List<People>> groups = list.stream()
.collect(Collectors.groupingBy(People::getHeight);
Then find which groups have only one person:
groups.entrySet().stream()
.filter(e -> e.getValue().size() == 1) // use only groups with one person
.map(e -> e.getValue().get(0))
.collect(Collectors.toList());
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.