Reputation: 17461
I have class Person
private String name;
private int age;
private Map<String, LocalDate> carsBoughWithDate;
You can ignore name and age. The important one here is carsBoughWithDate
Due to some reason I am saving person cars bough in a map with the date
Test Data
Map<String, LocalDate> carsbought = new HashMap<>();
carsbought.put("Toyota", LocalDate.of(2017, 2, 1));
carsbought.put("Corolla", LocalDate.of(2017, 2, 1));
Person john = new Person("John", 22, carsbought);
carsbought = new HashMap<>();
carsbought.put("Vauxhall", LocalDate.of(2017, 1, 1));
carsbought.put("BMW", LocalDate.of(2017, 1, 1));
carsbought.put("Toyota", LocalDate.of(2017, 1, 1));
Person michael = new Person("Michael", 44, carsbought);
List<Person> personList = new ArrayList<>();
personList.add(john);
personList.add(michael);
Output:
[Person{name='John', age=22, carsBoughWithDate={Toyota=2017-02-01, Corolla=2017-02-01}},
Person{name='Michael', age=44, carsBoughWithDate={Vauxhall=2017-01-01, Toyota=2017-01-01, BMW=2017-01-01}}]
Now, I have to find out the person which has bought cars but then sort the person who bought the car earliest on the top in the list
Example: search person who has cars "Toyota" or BMW
This is what I have done
**
System.out.println("Before sort >" + personList);
List<Person> sortedList = Lists.newArrayList();
HashMap<LocalDate, Person> collect = Maps.newHashMap();
for (Person person : personList) {
Map<String, LocalDate> docCarsBoughWithDate = person.getCarsBoughWithDate();
collect.putAll(docCarsBoughWithDate.entrySet().stream()
.filter(map -> Lists.newArrayList("Toyota", "BMW").contains(map.getKey()))
.collect(HashMap::new,
(m, v) -> m.put(
v.getValue(),
person),
HashMap::putAll
));
}
Map<String, List<Person>> collect1 = collect.entrySet().stream().sorted(Map.Entry.comparingByKey()).map(m -> m.getValue()).collect(Collectors.groupingBy(Person::getName));
collect1.keySet().forEach(key -> sortedList.add(collect1.get(key).get(0)));
System.out.println("after sort > " + sortedList
);
This all works
Before sort >
[Person{name='John', age=22, carsBoughWithDate={Toyota=2017-02-01, Corolla=2017-02-01}}, Person{name='Michael', age=44, carsBoughWithDate={Vauxhall=2017-01-01, Toyota=2017-01-01, BMW=2017-01-01}}]
after sort >
[Person{name='Michael', age=44, carsBoughWithDate={Vauxhall=2017-01-01, Toyota=2017-01-01, BMW=2017-01-01}}, Person{name='John', age=22, carsBoughWithDate={Toyota=2017-02-01, Corolla=2017-02-01}}]
I feel this is bit cumbersome. Can I simplify the logic?
Upvotes: 1
Views: 63
Reputation: 637
Here you go:
List<Person> sortedList = personList.stream() //
.flatMap(p -> p.getCarsBoughWithDate().entrySet().stream() //
.filter(e -> targetCarNames.contains(e.getKey())) // filter the bought cars which are in the target bought cars.
.sorted(Entry.comparingByValue()).limit(1) // sorted and only fetch the entry with earliest bought date.
.map(e -> new SimpleEntry<>(p, e.getValue()))) // composite a new entry with the person and the earliest bought date.
.sorted(Entry.comparingByValue()).map(e -> e.getKey()).collect(toList()); //
Upvotes: 2
Reputation: 12932
First of all, are you sure that "this all works"? I tried your code with your test data with the following additional person:
carsbought = new HashMap<>();
carsbought.put("BMW", LocalDate.of(2017, 2, 1));
Person sally = new Person("Sally", 25, carsbought);
and she overwrote John because she happened to have bought a car at the same date.
Second, the strategy to solve complex problems is to break them down into simpler problems. For example, I would first add a method which determines the first date at which a person bought one of a set of cars:
private Optional<LocalDate> firstDateOf(Person person, Collection<String> cars)
{
return person.getCarsBoughWithDate().entrySet().stream()
.filter(e -> cars.contains(e.getKey()))
.map(Map.Entry::getValue)
.min(Comparator.naturalOrder());
}
This will be the sort key of the people. Then use this method to map each person to the sort key and finally sort the list:
List<Person> sortCarOwners(Collection<Person> people, Collection<String> cars)
{
Map<Person, Optional<LocalDate>> personToDateMap = people.stream()
.collect(Collectors.toMap(p -> p, p -> firstDateOf(p, cars)));
return personToDateMap.entrySet().stream()
.filter(e -> e.getValue().isPresent())
.sorted(Comparator.comparing(e -> e.getValue().get()))
.map(e -> e.getKey())
.collect(Collectors.toList());
}
I don't know if you consider this "less cumbersome", but I hope it helps.
Upvotes: 1