3

I have a HashSet of Persons. A person has a firstName, lastName and age like: Person("Hans", "Man", 36)

My task is to get a list of the persons who are older than 17, sort them by age and concat the firstName with the lastName like: ["Hans Man","another name", "another name"]

Im just allowed to import:

import java.util.stream.Stream; import java.util.stream.Collectors; import java.util.List; import java.util.ArrayList;

My idea was to sort them first, map the names in separate Streams and to zip them, but it doesn't work.

public static void getNamesOfAdultsSortedByAge(Stream<Person> stream){

    Stream<Person> result = stream;
    Stream<Person> result1 = result.filter(p -> p.getAge() >= 18)
                            .sorted((x, y) -> Integer.compare(x.getAge(),y.getAge()));


    Stream<String> firstName = result1.map(Person::getFirstName);
    Stream<String> lastName = result1.map(Person::getLastName);

    Stream<String> result3 = concat(firstName, lastName);

    List<String> result4 = result3.collect(Collectors.toList());

    System.out.println(result4);
}

thank you in advance

Nicholas K
  • 15,148
  • 7
  • 31
  • 57
oddi
  • 79
  • 1
  • 8
  • 4
    You’re thinking too complicated. Just use `map(p -> p.getFirstName()+" "+p.getLastName())`. This has nothing to do with zipping. And don’t store each stream stage into another variable. Just chain the steps, `List result = stream.filter(p -> p.getAge() >= 18) .sorted(Comparator.comparingInt(Person::getAge)) .map(p -> p.getFirstName() + " " + p.getLastName()) .collect(Collectors.toList());` – Holger Nov 29 '18 at 10:53

5 Answers5

3

You could do so using :

public static void getNamesOfAdultsSortedByAge(Stream<Person> stream) {
    List<String> sorted = stream.filter(p -> p.getAge() >= 18)
                                .sorted((x, y) -> Integer.compare(x.getAge(),y.getAge()))
                                .map(e -> e.getFirstName() + " " + e.getLastName())
                                .collect(Collectors.toList());
    System.out.println(sorted);
}

Here we just map the sorted stream by concatenating the first name and then the last name, after which we use the .collect() terminal operation to collect it to a list.

Nicholas K
  • 15,148
  • 7
  • 31
  • 57
  • why did you edit it? the first one was the solution I was looking for because Im not allowed to import java.util.Comparator – oddi Nov 29 '18 at 12:19
  • Thought it was cleaner, missed out your constraints. Changed it back. – Nicholas K Nov 29 '18 at 13:24
  • @oddi what does this even mean "you are not allowed to import `java.util.Comparator`"? I've never heard of such a strange import agreement... but you know that you can also use: `java.util.Comparator.comparingInt` and no import would be visible? ;-) – Roland Nov 29 '18 at 13:24
  • @Roland : I believe an up-vote is in-order for the confusion caused ;) – Nicholas K Nov 29 '18 at 13:28
  • @NicholasK you may rather want to look up my answer instead ;-) – Roland Nov 29 '18 at 13:44
  • @NicholasK by the way... you know that you can also easily "rollback" a change? (just look at the revisions... there is its own "rollback"-link...) just in case you require that again at some time... – Roland Nov 29 '18 at 13:58
  • @Roland I´m a student and the tasks are always to complete codes with deleted methods without changing anything. Its really annoying but i have to deal with it. – oddi Nov 29 '18 at 15:11
  • well... then even more so I (clearly my personal opinion) would use the `Comparator`... whoever made that assignment/task probably didn't know it him/herself... why else would he/she used that construct otherwise? So: sharing is caring... I would at least report back the usage of `Comparator.comparingInt` ;-) – Roland Nov 29 '18 at 15:16
  • Suggestion: While you were editing, you could've kept both the solutions in your answers as alternates. Just that `Comparator.comparingInt` shouldn't really have been another answer :) – Naman Nov 29 '18 at 17:15
2
public static void main(String[] args) {
    final List<String> matching = Lists.newArrayList(
            new Person("Joey", "Tribiani", 28),
            new Person("Rachel", "Green", 12),
            new Person("Ross", "Geller", 114),
            new Person("Chandler", "Bing", 17)).stream()
            .filter(person -> person.getAge() > 17)
            .sorted(Comparator.comparing(Person::getAge))
            .map(person -> person.getFirstName() + " " + person.getLastName())
            .collect(toList());
}

If you need to change sorting order just reverse the comparator:

Comparator.comparing(Person::getAge).reversed()
g-t
  • 1,455
  • 12
  • 17
  • Why do you think the comparator needs to be `reversed()`? – Holger Nov 29 '18 at 11:01
  • 1
    Because you've written "sort them by age" not mentioning the ordering. Wanted to show how to control items ordering. – g-t Nov 29 '18 at 11:22
  • didn't need it, but im glad to know reversed() now – oddi Nov 29 '18 at 11:25
  • @g-t I did not write anything about it, but the OP provided a code example which contains a comparator clearly using ascending order. – Holger Nov 29 '18 at 14:55
  • Fine. Removed reversed() but left a note for someone who might need descending order. – g-t Nov 30 '18 at 15:14
1

This doesn't work:

Stream<String> firstName = result1.map(Person::getFirstName);
Stream<String> lastName = result1.map(Person::getLastName);

After the first map, the Stream is of type String which doesn't fit Person::getLastName. You need to concat within the first map() call itself.

daniu
  • 14,137
  • 4
  • 32
  • 53
  • Ah okay, now I understand the Exception: java.lang.IllegalStateException: stream has already been operated upon or closed, thanks – oddi Nov 29 '18 at 11:30
1

Inside getNamesOfAdultsSortedByAge method:

stream
    .filter(p -> p.getAge() > 17)
    .sorted(Comparator.comparingInt(Person::getAge))
    .map(person -> person.getFirstName() + " " + person.getLastName())
    .collect(Collectors.toList())

I suppose it should suit your needs. filter filters people that are only 18 or older, second line sorts given by getAge predicate, third just maps Person instance to a string containing %firstName% %lastName%, and fourth collects the result into a list.

nyarian
  • 4,085
  • 1
  • 19
  • 51
1

I would use the following and as you have strange rules regarding the imports, I hide that one for Comparator deliberately:

List<String> result = stream.filter(p -> p.getAge() >= 18)
                            .sorted(java.util.Comparator.comparingInt(Person::getAge))
                            .map(p -> p.getFirstName() + " " + p.getLastName())
                            .collect(Collectors.toList());

Note: I know of some rules that imply that no other dependency should be used than the one listed on the "allowed list of dependencies", but I've never heard of a rule that only allows to use like 4 imports but disallows one of the most important ones. If Comparator would be an internal interface/class I could understand it, but it's an essential interface. You even use it as a functional interface if you write (x, y) -> Integer.compare(x.getAge(),y.getAge()), so I really don't get why this import shouldn't be allowed. That being said: my solution does not require you to use an import to java.util.Comparator. Have fun using it. It really makes comparisons easier and less error-prone (just imagine two similarly named methods and you catched the wrong one by mistake... have fun finding that error ;-)).

Roland
  • 22,259
  • 4
  • 57
  • 84
  • I am exactly your opinion, tanks for your detailed comment, I didn't know that you can use it that way. – oddi Nov 29 '18 at 15:27