0

Lets say that I have a document that looks like this:

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class main {

    public static void main(String[] args) {

        List<Person> people = Arrays.asList(
                new Person("New York", "foo", "bar"),
                new Person("New York", "bar", "foo"),
                new Person("New Jersey", "foo", "bar"),
                new Person("New Jersey", "bar", "foo")
        );

    }

    public static class Person {
        public String city;
        public String firstName;
        public String lastName;

        Person(String city, String firstName, String lastName) {
            this.city = city;
            this.firstName = firstName;
            this.lastName = lastName;
        }
    }
}

How would I be able to use streams to only get one person from each city and return it into a list?

Gabriel Gavrilov
  • 337
  • 3
  • 11

1 Answers1

1

You can collect the entries into a map, using Person::getCity, and then map the entry values and grab the first one.

import java.util.*;
import java.util.AbstractMap.SimpleEntry;
import java.util.Map.Entry;
import java.util.function.Function;
import java.util.stream.Collectors;

public class App {
    public static void main(String[] args) {
        List<Person> people = Arrays.asList(
                new Person("New York", "foo", "bar"),
                new Person("New York", "bar", "foo"),
                new Person("New Jersey", "foo", "bar"),
                new Person("New Jersey", "bar", "foo"));

        List<Person> firstByCity = groupBy(people, Person::getCity)
                .entrySet().stream()
                .map(e -> e.getValue().get(0))
                .collect(Collectors.toList());

        System.out.println(firstByCity);
    }

    // Source: https://stackoverflow.com/a/75377044/1762224
    public static <E, K, V> Map<K, List<V>> groupBy(
            Collection<E> collection, Function<E, K> keyFn, Function<E, V> valueFn) {
        return collection.stream()
                .map(item -> new SimpleEntry<K, V>(keyFn.apply(item), valueFn.apply(item)))
                .collect(Collectors.groupingBy(Entry::getKey,
                        Collectors.mapping(Entry::getValue, Collectors.toList())));
    }

    public static <E, K> Map<K, List<E>> groupBy(Collection<E> collection, Function<E, K> keyFn) {
        return groupBy(collection, keyFn, Function.identity());
    }

    public static class Person {
        public String city;
        public String firstName;
        public String lastName;

        Person(String city, String firstName, String lastName) {
            this.city = city;
            this.firstName = firstName;
            this.lastName = lastName;
        }

        public String getCity() {
            return city;
        }

        @Override
        public String toString() {
            return String.format("{ city: %s, firstName: %s, lastName: %s }",
                city, firstName, lastName);
        }

    }
}

Output

[
  { city: New York, firstName: foo, lastName: bar },
  { city: New Jersey, firstName: foo, lastName: bar }
]
Mr. Polywhirl
  • 42,981
  • 12
  • 84
  • 132