Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use multiple streams and .map functions in java 8 with lambda expressions

I have a List counties which contains unique county names only, and a List txcArray which contains a city name, county name and population for that city.

I need to get the largest city name of each county from txcArray using only Java 8 with lambda expressions and Streams.

Here is the code I have so far:

List<String> largest_city_name = 
    counties.stream() 
            .map(a -> txcArray.stream()
                              .filter(b ->  b.getCounty().equals(a))
                              .mapToInt(c -> c.getPopulation())
                              .max())
            .collect( Collectors.toList());

I am trying to add another .map statement after .max() to get the name of the City with the largest population but my new lambda expression does not exists from the stream of txcArray it only recognizes it as an int type and a texasCitiesClass type. Here is what I am trying to do.

 List<String> largest_city_name = 
     counties.stream() 
             .map(a -> txcArray.stream()
                               .filter( b ->  b.getCounty().equals(a))
                               .mapToInt(c->c.getPopulation())
                               .max()
                               .map(d->d.getName()))
             .collect( Collectors.toList());

Can someone tell me what I am doing wrong?

like image 948
Octavio garcia Avatar asked Oct 11 '17 01:10

Octavio garcia


2 Answers

You don't need the counties list altogether. Just stream txcArray and group by county:

Collection<String> largestCityNames = txcArray.stream()
        .collect(Collectors.groupingBy(
                City::getCounty,
                Collectors.collectingAndThen(
                        Collectors.maxBy(City::getPopulation),
                        o -> o.get().getName())))
        .values();
like image 80
shmosel Avatar answered Sep 18 '22 06:09

shmosel


Well, once to map the Stream of cities into an IntStream, there's no way for you to recover the name of the city corresponding with the int value.

Use Stream's max instead of converting to IntStream:

List<String> largest_city_name =
    counties.stream() 
            .map(a -> txcArray.stream()
                              .filter(b ->  b.getCounty().equals(a))
                              .max(Comparator.comparingInt(City::getPopulation))
                              .get())
            .map(City::getName)
            .collect(Collectors.toList());

This way the map operation maps each county to its City with the highest population. Note that max returns an Optional<City>, so it the Optional is empty (i.e. some county has no cities), get() will throw an exception.

To avoid that issue, you can write:

List<String> largest_city_name =
    counties.stream() 
            .map(a -> txcArray.stream()
                              .filter(b ->  b.getCounty().equals(a))
                              .max(Comparator.comparingInt(City::getPopulation))
                              .map(City::getName)
                              .orElse(""))
            .collect(Collectors.toList());

This will map a county having no cities into an empty String.

This code assumes txcArray is a List<City>, where City is:

class City { public String getName () {return nam;} public int getPopulation() {return pop;} public String getCounty() {return cnt;} String nam; int pop; String cnt; public City(String nam,int pop,String cnt) { this.nam = nam; this.pop = pop; this.cnt = cnt; } }

and counties is a List<String>. If my assumptions are not accurate, you'll have to make some adjustments.

Now, testing the code with the following Lists:

List<String> counties=new ArrayList<> ();
counties.add ("First");
counties.add ("Second");
counties.add ("Third");
counties.add ("Fourth");
List<City> txcArray = new ArrayList<> ();
txcArray.add (new City("One",15000,"First"));
txcArray.add (new City("Two",12000,"First"));
txcArray.add (new City("Three",150000,"Second"));
txcArray.add (new City("Four",14000,"Second"));
txcArray.add (new City("Five",615000,"Third"));
txcArray.add (new City("Six",25000,"Third"));

produces this output List:

[One, Three, Five, ]
like image 29
Eran Avatar answered Sep 20 '22 06:09

Eran