2015-06-27 2 views
4

У меня естьПреобразование в карты с помощью Java 8 и лямбды

List<Gift> gifts = new ArrayList<>(); 
gifts .add(new Gift().withType(INF, CHD)); 
gifts .add(new Gift().withType(ADT, CHD)); 
gifts .add(new Gift().withType(INF, ADT)); 

подарков имеет метод List<Type> getTypes();

и теперь я хотел бы преобразовать список подарков в нечто вроде Map<Type,List<Gift>>. Я хотел бы сделать это с Java 8 и lambdas в одной строке. Является ли это возможным?

public class Gift { 

    public List<Type> getTypes() { 
     return types; 
    } 

    public Gift withType(Type... types) { 
     this.types = Arrays.asList(types); 
     return this; 
    } 

    List<Type> types = new ArrayList<>(); 
} 

public enum Type { 
    ADT, 
    CHD, 
    INF; 
} 

Предыдущий старый код (он выглядит ужасно). Это все, что у меня есть.

Map<Type, List<Gift>> byTypes = new HashMap<>(); 

for (Gift gift : gifts) { 
    for (Type type : gift.getTypes()) { 
     List<Gift> giftList = byTypes.get(type); 
     if (giftList == null) { 
      giftList = new ArrayList<>(); 
     } 
     giftList.add(gift); 
     byTypes.put(type,giftList); 
    } 
} 
+0

Итак, у каждого 'Gift' есть два' 'Type ', связанных с ним? Можете ли вы показать свой класс «Подарок»? Кроме того, как определить «Подарок» как уникальный «Подарок». Это важно, потому что вам нужно знать, что такое «ключ» для «Карты» – CKing

+0

. Что относительно моего второго вопроса? * Также, как определить подарок как уникальный подарок *. – CKing

+0

Нет специального метода для indentify Подарок –

ответ

3

Использование гуавы-х Multimap:

ListMultimap<Type, Gift> multimap = ArrayListMultimap.create(); 

gifts.forEach(g -> g.getTypes().forEach(t -> multimap.put(t, g))); 

Map<Type, Collection<Gift>> map = multimap.asMap(); 
+0

Не хотите сказать 'forEach (t -> multimap.put (t, g))'? – Makoto

+1

Да, спасибо. Я обновил его – Robert

+0

ОК, но здесь все еще есть «промежуточный» элемент (мультимап). Мне интересно, можно ли опустить его. Использование только потоков и лямбда. –

1

Хорошо, я нашел решение, которое мне :-) отвечают соответствующим требованиям я написал сборщика :-D

Map<Type, List<Gift>> collect1 = gifts.stream().collect(new TypeToManyGiftCollector()); 

public class TypeToManyGiftCollector 
     implements Collector<Gift, Map<Type, List<Gift>>, Map<Type, List<Gift>>> { 

    @Override 
    public Supplier<Map<Type, List<Gift>>> supplier() { 
     return() -> new HashMap<Type, List<Gift>>() {{ 
      for (Type type : Type.values()) { 
       put(type, new ArrayList<Gift>()); 
      } 
     }}; 
    } 

    @Override 
    public BiConsumer<Map<Type, List<Gift>>, Gift> accumulator() { 
     return (Map<Type, List<Gift>> map, Gift gift) -> { 
      gift.getTypes().stream().forEach(type -> map.get(type).add(gift)); 
     }; 
    } 

    @Override 
    public BinaryOperator<Map<Type, List<Gift>>> combiner() { 
     return (Map<Type, List<Gift>> map1, Map<Type, List<Gift>> map2) -> 
     { 
      for (Type type : Type.values()) { 
       map1.get(type).addAll(map2.get(type)); 
      } 
      return map1; 
     }; 
    } 

    @Override 
    public Function<Map<Type, List<Gift>>, Map<Type, List<Gift>>> finisher() { 
     return Function.identity(); 
    } 

    @Override 
    public Set<Characteristics> characteristics() { 
     return Collections.unmodifiableSet(EnumSet.of(IDENTITY_FINISH)); 
    } 
} 
+0

Мне просто нравится, как вы ставили инициализацию 'HashMap' в методе' supplier() 'в нечто синтаксическую красоту и элегантность. Думаю, я могу читать ваш код как роман. – YoYo

0

Повторное введение ваш промежуточный класс Pair P, но несколько иначе. Я думаю, мы могли бы ожидать, что в более поздних итерациях Java это станет намного более распространенным местом и будет легче сделать с введением встроенного типа пары и реализацией Value Objects.

package play; 

import java.io.IOException; 
import java.util.ArrayList; 
import java.util.EnumMap; 
import java.util.List; 
import java.util.Map; 
import java.util.stream.Collectors; 
import static play.Type.*; 

public class Play { 
    static class P<K,V> { K k; V v; P(K kk,V vv) {k=kk;v=vv;}} 
    public static void main(String[] args) throws IOException { 
    List<Gift> gifts = new ArrayList<>(); 
    gifts .add(new Gift().withType(INF, CHD)); 
    gifts .add(new Gift().withType(ADT, CHD)); 
    gifts .add(new Gift().withType(INF, ADT)); 
    Map<Type,List<Gift>> m = gifts.stream() 
     .flatMap((g)->g.getTypes().stream().map((t)->new P<>(t,g))) 
     .collect(
     Collectors.groupingBy(
      (p)->p.k, 
      // Does not work with <code>new EnumMap<>(Type.class)</code> 
      // I dont know why, ... 
     ()->new EnumMap(Type.class), 
      Collectors.mapping(
      (p)->p.v, 
      Collectors.toList() 
     ) 
     ) 
    ); 
    System.out.println("Map: "+m.toString()); 
    } 
} 

Моя единственная проблема в этом коде, что я не могу объяснить потребность в «нетипизированный» Карта как карта завода. Не стесняйтесь объяснять, знаете ли вы, почему ...

0

Я нашел другое решение с методом уменьшения. На мой взгляд, меньше и проще понять.

 HashMap<Type, List<Gift>> result = gifts.stream().reduce(
      new HashMap<Type, List<Gift>>() {{ 
       asList(Type.values()).stream().forEach(type -> put(type, new ArrayList<>())); 
      }} 
      , 
      (map, gift) -> { 
       gift.getTypes().stream().forEach(type -> map.get(type).add(gift)); 
       return map; 
      } 
      , 
      (map1, map2) -> { 
       asList(Type.values()).stream().forEach(type -> map1.get(type).addAll(map2.get(type))); 
       return map1; 
      } 
    ); 
Смежные вопросы