Java: how to transform from List to Map without iterating

前端 未结 4 1707
予麋鹿
予麋鹿 2020-12-30 03:56

I have a list of objects that I need to transform to a map where the keys are a function of each element, and the values are lists of another function of each element. Effec

4条回答
  •  粉色の甜心
    2020-12-30 04:56

    Guava has Maps.uniqueIndex(Iterable values, Function keyFunction) and Multimaps.index(Iterable values, Function keyFunction), but they don't transform the values. There are some requests to add utility methods that do what you want, but for now, you'll have to roll it yourself using Multimaps.index() and Multimaps.transformValues():

    static class Person {
        private final Integer age;
        private final String name;
    
        public Person(Integer age, String name) {
            this.age = age;
            this.name = name;
        }
    
        public Integer getAge() {
            return age;
        }
    
        public String getName() {
            return name;
        }
    }
    
    private enum GetAgeFunction implements Function {
        INSTANCE;
    
        @Override
        public Integer apply(Person person) {
            return person.getAge();
        }
    }
    
    private enum GetNameFunction implements Function {
        INSTANCE;
    
        @Override
        public String apply(Person person) {
            return person.getName();
        }
    }
    
    public void example() {
        List persons = ImmutableList.of(
                new Person(100, "Alice"),
                new Person(200, "Bob"),
                new Person(100, "Charles"),
                new Person(300, "Dave")
        );
    
        ListMultimap ageToNames = getAgeToNamesMultimap(persons);
    
        System.out.println(ageToNames);
    
        // prints {100=[Alice, Charles], 200=[Bob], 300=[Dave]}
    }
    
    private ListMultimap getAgeToNamesMultimap(List persons) {
        ImmutableListMultimap ageToPersons = Multimaps.index(persons, GetAgeFunction.INSTANCE);
        ListMultimap ageToNames = Multimaps.transformValues(ageToPersons, GetNameFunction.INSTANCE);
    
        // Multimaps.transformValues() returns a *lazily* transformed view of "ageToPersons"
        // If we want to iterate multiple times over it, it's better to create a copy
        return ImmutableListMultimap.copyOf(ageToNames);
    }
    

    A re-usable utility method could be:

    public static  ImmutableListMultimap keyToValuesMultimap(Iterable elements, Function keyFunction, Function valueFunction) {
        ImmutableListMultimap keysToElements = Multimaps.index(elements, keyFunction);
        ListMultimap keysToValuesLazy = Multimaps.transformValues(keysToElements, valueFunction);
        return ImmutableListMultimap.copyOf(keysToValuesLazy);
    }
    

    I guess we could improve the generics in the signature by using Function or something, but I don't have the time to delve further...

提交回复
热议问题