2016-02-28 5 views
3

У меня есть iteraror, где в каждой итерации I'm создавая новую картуJava 8 карт Объединить в итераторе

Map<String, List<String>> 

Теперь я хотел бы объединить в каждой итерации последней излучаемой карты с новым.

Если я посылаю список элементов getMap

{"a","a","b"} 

Я ожидаю получить карту

["a",{"foo:a", "foo:a"}, "b",{"foo:b"}] 

Я пытаюсь использовать уменьшить функцию, а потому, что putall работает только если я использую Multimap а не карта, не является хорошим вариантом.

Вот мой код

public Map<String, List<String>> getMap(List<String> items){ 
     return items().stream() 
       .map(item -> getNewMap(item) --> Return a Map<String, List<String>> 
       .reduce(new HashMap<>(), (o, p) -> { 
        o.putAll(p); 
        return o; 
       }); 
} 

public Map<String, List<String>> getNewMap(String item){ 
    Map<String, List<String>> map = new HashMap<>(); 
    map.put(item, Arrays.asList("foo:" + item)); 
    return map; 
}  

I'm не ищет не многословный способ сделать это.

+1

Подумайте о принятии решения Холгера вместо моего, это намного чище и лучше. – Tunaki

ответ

4

Что вы хотите, это плоская карта каждой промежуточной карты к ее записям и сделать из нее одну карту.

В следующем коде каждый элемент сопоставляется с соответствующей картой. Затем каждое отображение плоское отображается на его записи, и поток собирается в карту.

public static void main(String[] args) { 
    System.out.println(getMap(Arrays.asList("a", "a", "b"))); 
    // prints "{a=[foo:a, foo:a], b=[foo:b]}" 
} 

public static Map<String, List<String>> getMap(List<String> items) { 
    return items.stream() 
       .map(item -> getNewMap(item)) 
       .flatMap(m -> m.entrySet().stream()) 
       .collect(Collectors.toMap(
        Map.Entry::getKey, 
        Map.Entry::getValue, 
        (l1, l2) -> { List<String> l = new ArrayList<>(l1); l.addAll(l2); return l; } 
       )); 
} 

public static Map<String, List<String>> getNewMap(String item) { 
    Map<String, List<String>> map = new HashMap<>(); 
    map.put(item, Arrays.asList("foo:" + item)); 
    return map; 
} 

В случае с несколькими ключами это добавляет каждый список вместе.

+0

Работает очень хорошо, спасибо за этот урок. – paul

+0

Создание карт только для плоской карты дает впечатляющий код, демонстрирующий все функции потокового API, но я думаю, что первоначальный подход OP запустил вас в это барочное решение. Начиная с нуля и используя правильный инструмент, вы получаете [гораздо более простое решение] (http://stackoverflow.com/a/35699445/2711488). И, как последнее замечание, когда вам действительно нужна единственная запись «Карта», рассмотрите ['singletonMap'] (https://docs.oracle.com/javase/8/docs/api/java/util/Collections.html # singletonMap-KV-) ... – Holger

+0

@Holger Вы правы, что для этого конкретного экземпляра можно сделать это намного проще. Но что, если внутренние карты '[foo: ..., bar: ...]'? – Tunaki

4

Всякий раз, когда вы хотите получить Map<…, List<…>> из потока, вы должны сначала проверить, как подходит groupingBy collector. В его простейшей форме он получает функцию группировки, которая определяет ключи результирующей карты и собирает все элементы группу в список. Так как вы хотите префикс "foo:" предваряется, вам придется customize this group collector вставив mapping operation перед collecting the items into a list:

public static Map<String, List<String>> getMap(List<String> items) { 
    return items.stream().collect(Collectors.groupingBy(
     Function.identity(), 
     Collectors.mapping("foo:"::concat, Collectors.toList()))); 
} 

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

+0

Спасибо за новое решение. Но про конкат элемента «foo:» + была только часть примера, на самом деле мы не делаем этого в реальном коде.Я посмотрю на это решение, как только смогу. – paul

+0

Не имеет значения, используете ли вы '' foo: ":: concat' или' x -> "foo:" + x' или любую подходящую функцию сопоставления. Логика не меняется. – Holger

+0

getNewMap() - это всего лишь примерный метод, реальное приложение, которое возвращает Map > с более сложной бизнес-логикой, поэтому функция Collectors.mapping (Function) выглядит бесполезной. Но я изучу ваш код, и я увижу, можно ли его использовать. Еще раз спасибо. – paul

Смежные вопросы