Преобразовать List‹Object› в Map‹String, List‹Object›› и выделить дубликаты в соответствии с некоторыми свойствами элемента List?

Например, для двух таких классов:

Class RawItem {
    private String category;
    private int code;
    private String name;
}

Class Item {
    private int code;
    private String name;
}

И список RawItem следующим образом:

[ { "категория": "а", "код": 1, "имя": "элемент1" }, { "категория": "а", "код": 1, "имя": "элемент1" }, { «категория»: «а», «код»: 2, «имя»: «элемент2» }, { «категория»: «б», «код»: 1, «имя»: «элемент1» }, { «категория» ":"b", "code":1, "name":"item1" } ]

Превратите его в Map<String, List<Item>> вот так:

{
   "a":[
      {
         "code":1,
         "name":"item1"
      },
      {
         "code":2,
         "name":"item2"
      }
   ],
   "b":[
      {
         "code":1,
         "name":"item1"
      }
   ]
}

Любой ответ будет принят с благодарностью. Спасибо.


person Wuaner    schedule 19.03.2018    source источник
comment
Пожалуйста, опубликуйте свою попытку   -  person user7    schedule 19.03.2018
comment
Если это в основном код, вам следует рассмотреть возможность более подробного описания вашей проблемы, рассказав, где вы нашли проблему (что потребует публикации вашей попытки)   -  person Cleptus    schedule 19.03.2018
comment
List<RawItem> в Map<String, Set<Item>> было бы лучше всего, хотя Item потребовалось бы equals+hashCode.   -  person Joop Eggen    schedule 19.03.2018
comment
Мне нужно сохранить порядок исходного списка   -  person Wuaner    schedule 19.03.2018
comment
В основном это код, потому что я процитировал не код как код, вот и все. Проблема уже описана ясно   -  person Wuaner    schedule 19.03.2018
comment
И я не знаю, как это решить.   -  person Wuaner    schedule 19.03.2018


Ответы (1)


Следующие groupingBy должны работать. В рамках ваших дополнительных требований мы знаем, что нельзя использовать метод equals объектов RawItem, поэтому мы используем фильтр вместо метода Stream distinct (*):

    Set<Object> seen = ConcurrentHashMap.newKeySet();

    Map<String, List<Item>> m = 
       l.stream()
        .filter(item -> seen.add(item.category + ":" + item.name + ":" + item.code))
        .collect(Collectors.groupingBy(item -> item.category,
            Collectors.mapping(item -> new Item(item.code, item.name), 
                               Collectors.toList())));

Обратите внимание, что для того, чтобы метод distinct работал и удалял дубликаты, вам необходимо иметь правильную реализацию методов hashCode и equals в классе RawItem.

Например, следующий тест:

List<RawItem> list = Arrays.asList(new RawItem("a", 1, "dfg"),
                                   new RawItem("a", 1, "dfg"),
                                   new RawItem("a", 1, "fdgdfdfgdg"),
                                   new RawItem("b", 1, "dfg"));

Map<String, List<Item>> map = // the above

System.out.println(map);

дает

{
   a=[Item{code=1, name='dfg'}, Item{code=1, name='fdgdfdfgdg'}],
   b=[Item{code=1, name='dfg'}]
}

(*) Изменить:
Как поделился OP, следующие сообщения помогают разработать решение на основе настраиваемого отношения эквивалентности с потоковым API, когда distinct() нельзя использовать:

person Alexandre Dupriez    schedule 19.03.2018
comment
Это не решает проблему полностью, так как не избавляет от элементов с одинаковым содержимым (дубликатов). - person Claudiu Guja; 19.03.2018
comment
@ClaudiuGuja Действительно, исправил пост. - person Alexandre Dupriez; 19.03.2018
comment
Спасибо за быстрый ответ, я попробую tmrw, потому что я уже не работаю после того, как задал этот вопрос, сейчас я использую свой телефон для комментирования... но поскольку для Different() нужна правильная реализация equals, я сомневаюсь, что это работает, так как я не могу использовать категорию, код, имя для уникальной идентификации RawItem, у него есть другие ключевые поля, которые здесь не перечислены. Итак, любое другое решение в качестве дополнительного? - person Wuaner; 19.03.2018
comment
@Wuaner: Конечно, я обновил сообщение, чтобы учесть это дополнительное требование. - person Alexandre Dupriez; 19.03.2018
comment
@AlexandreDupriez Так гениально~ Не могу проверить сейчас, потому что рядом нет компьютера, но я знаю, что это сработает! Принято и еще раз спасибо. - person Wuaner; 19.03.2018
comment
Это работает ~ спасло мой день, и я извлекаю набор видимый как предикат как 1 2 3 показано . - person Wuaner; 20.03.2018
comment
@Wuaner Спасибо за отзыв, я добавил эти ссылки в пост. Я также могу обновить его, чтобы заменить набор seen предикатом, как вы упомянули? - person Alexandre Dupriez; 20.03.2018
comment
@AlexandreDupriez Я уже поработал с предикатом, но было бы здорово, если бы мы разместили его здесь для некоторых других, я думаю? Большое спасибо за это решение, кстати. - person Wuaner; 21.03.2018