Java 8 Список объектов для сопоставленияценностей - PullRequest
0 голосов
/ 15 мая 2018

Я пытаюсь преобразовать List<Object> в Map<String, List>, используя Streams,

public class User{
   String name;
   String age;
   String org;
}

У меня есть List<Users>, и мне нужно собрать в Map<String, Object> m,

 m.put("names", List of names,);
 m.put("age", List of age);
 m.put("org", List of org);

для использования в именованном запросе -> например: select * from table ... where names in (:names) and age in (:age) and org in (:org)

на данный момент я делаю как

List<String> names = userList.stream().map(User::getName).collect(Collectors.toList());
List<String> age= userList.stream().map(User::getAge).collect(Collectors.toList());
List<String> org= userList.stream().map(User::getName).collect(Collectors.toList());

Как собрать все значения при потоковой передаче только в списокодин раз?

Ответы [ 4 ]

0 голосов
/ 15 мая 2018

Попробуйте это. Цветной бин, используемый для отделения значения карты и ключа от списка.

    List<Color> colors = new ArrayList<Color>();

    colors.add(new Color("RED", "#FF0000"));
    colors.add(new Color("BLUE", "#0000FF"));
    colors.add(new Color("GREEN", "#008000"));

    // construct key-value pairs from name and code fields of Color
    Map<String, String> map = colors.stream()
                                .collect(Collectors.toMap(Color::getName, 
                                                        Color::getCode));
0 голосов
/ 15 мая 2018

Эран показал вам , как вы можете сделать это с помощью потоков.Как вы можете надеяться, это невероятно некрасиво.

Если ваша проблема с процедурной версией заключается в дублировании кода, есть и другие способы, помимо потоков, которые мы можем использовать для решения этой проблемы.

Я бы перестроил коллекцию по своему собственному методу:

private static List<String> getProperty(List<User> users, Function<User, String> getter) {
    return users.stream().map(getter).collect(Collectors.toList());
}

Map<String,List<String>> map = new HashMap<>();
map.put("names", getProperty(userList, User::getName));
map.put("age",   getProperty(userList, User::getAge));
map.put("org",   getProperty(userList, User::getOrg));
0 голосов
/ 15 мая 2018

Универсальный раствор

И @Eran, и @Michael дают хорошее решение, я хотел бы решить вашу проблему общим способом:

public static void main(String[] args) throws IllegalArgumentException, IllegalAccessException {
    List<User> listUsers = ...
    //Create a List which hold name of field and its value
    List<Map<String, Object>> listMapping = new ArrayList<>();
    for (User user : listUsers) {
        listMapping.add(fieldNameValue(user));
    }

    //Here group by the name of the field
    Map<String, List<Object>> result = listMapping.stream()
            .flatMap(a -> a.entrySet().stream())
            .collect(Collectors.groupingBy(Map.Entry::getKey,
                            Collectors.mapping(Map.Entry::getValue, Collectors.toList())));

}

//This method return a Map which hold names of attributes and its values.
static Map<String, Object> fieldNameValue(Object obj) throws IllegalArgumentException, IllegalAccessException {
    Map<String, Object> mapping = new HashMap<>();
    for (Field field : obj.getClass().getDeclaredFields()) {
        field.setAccessible(true);
        mapping.put(field.getName(), field.get(obj));
    }
    return mapping;
}

В этом решении вас не волнует количество полей типа.

0 голосов
/ 15 мая 2018

Я считаю, что-то вроде этого должно работать:

Map<String,List<String>> map =
    userList.stream()
            .flatMap(user -> {
                Map<String,String> um = new HashMap<>();
                um.put("names",user.getName());
                um.put("age",user.getAge());
                um.put("org",user.getOrg());
                return um.entrySet().stream();
            }) // produces a Stream<Map.Entry<String,String>>
            .collect(Collectors.groupingBy(Map.Entry::getKey,
                                           Collectors.mapping(Map.Entry::getValue,
                                                              Collectors.toList())));

Он преобразует каждый User в Map<String,String> (содержащий 3 обязательных свойства, проиндексированных необходимыми ключами), а затем группирует записи всех пользовательских карт по их ключам.

EDIT:

Вот еще одна альтернатива, которая создает Map.Entry s напрямую вместо создания маленьких HashMap s, поэтому она должна быть более эффективной:

Map<String,List<String>> map =
    userList.stream()
            .flatMap (user -> Stream.of (new SimpleEntry<>("names",user.getName()),
                                         new SimpleEntry<>("age",user.getAge()),
                                         new SimpleEntry<>("org",user.getOrg())))
            .collect(Collectors.groupingBy(Map.Entry::getKey,
                                           Collectors.mapping(Map.Entry::getValue,
                                                              Collectors.toList())));
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...