2017-09-27 2 views
2

Ich habe eine LinkedHashMap, die mehrere Einträge enthält. Ich möchte die mehreren Einträge im ersten Schritt auf einen einzigen reduzieren und diesen dann auf einen einzigen String abbilden. Zum Beispiel: ich mit einer Karte wie diese bin ab:Java 8 Stream reduzieren Karte

{"<a>"="</a>", "<b>"="</b>", "<c>"="</c>", "<d>"="</d>"} 

Und schließlich möchte ich so einen String erhalten:

<a><b><c><d></d></c></b></a> 

(In diesem Fall wird der String enthält die Schlüssel in Reihenfolge, als die Werte in umgekehrter Reihenfolge. Aber das ist nicht wirklich wichtig, ich möchte eine allgemeine Lösung)

Ich denke, ich brauche map.entrySet(). stream(). reduce(), aber ich habe keine Ahnung, was in der Reduce-Methode geschrieben werden soll und wie weitergemacht werden soll.

+0

Es ist nicht klar, was Sie mit "reduzieren Sie die mehrere Einträge auf einen einzigen". Ein einziger von was? Ein einziger Eintrag? Und was meinst du mit einer allgemeinen Lösung? – gdejohn

+0

Ich möchte mehrere Einträge auf einen einzelnen Eintrag mit einer Funktion reduzieren. Die reduce() -Methode verwendet BinaryOperator. In meinem Beispiel erhält dieser BinaryOperator zwei Einträge, concats die zwei Schlüssel und "reverse concats" die zwei Werte. Aber ich weiß nicht, wie ich es umsetzen soll. Auch die reduce() benötigt ein Identity-Element –

+2

Ist die Existenz eines intermediate reduced entry wirklich eine Voraussetzung? Das widerspricht der Aussage "Ich hätte gerne eine allgemeine Lösung". Z.B. Sie könnten einfach 'String result = String.join (" ", map.keySet()) + map.values ​​() verwenden. stream(). reduce (" ", (a, b) -> b + a);' . Wenn Sie auf einer einzigen "Stream" -Operation bestehen, können Sie 'String result = Stream.concat (map.keySet(). Stream(), map.values ​​(). Stream() verwenden. Collect (ArrayDeque :: new, ArrayDeque :: addFirst, (a, b) -> b.descendingIterator(). ForEachRemaining (a :: addFirst)). Stream()) .collect (Collectors.joining()); 'ohne' Map.Entry'-Instanzen zu konstruieren . – Holger

Antwort

4

Da Sie reduzieren Einträge Durch Verketten von Schlüsseln mit Schlüsseln und Werten mit Werten ist die gesuchte Identität ein Eintrag mit leeren Strings für Schlüssel und Wert.

String reduceEntries(LinkedHashMap<String, String> map) { 
    Entry<String, String> entry = 
     map.entrySet() 
      .stream() 
      .reduce(
       new SimpleImmutableEntry<>("", ""), 
       (left, right) -> 
        new SimpleImmutableEntry<>(
         left.getKey() + right.getKey(), 
         right.getValue() + left.getValue() 
        ) 
      ); 
    return entry.getKey() + entry.getValue(); 
} 

Java 9 fügt eine statische Methode Map.entry(key, value) für unveränderliche Einträge zu schaffen.

+0

Das ist die funktionale Lösung, an die ich gedacht habe . Könnte eine Erklärung verwenden. –

+0

Danke, das sollte es tun. Mein Hauptproblem war, dass Eintrag nicht instanziiert werden kann. Der SimpleImmutableEntry sollte das Problem lösen. –

+0

Es gibt mir "Inkompatible Parametertypen in Lambda-Ausdruck" –

0

hier ist ein Beispiel, wie ich es tun würde:

import java.util.LinkedHashMap; 

public class Main { 

    static String result = ""; 

    public static void main(String [] args) 
    { 
     LinkedHashMap<String, String> map = new LinkedHashMap<String, String>(); 
     map.put("<a>", "</a>"); 
     map.put("<b>", "</b>"); 
     map.put("<c>", "</c>"); 
     map.put("<d>", "</d>"); 

     map.keySet().forEach(s -> result += s); 
     map.values().forEach(s -> result += s); 

     System.out.println(result); 
    } 
} 

Hinweis: Sie können Werte reverse() mit ArrayUtils.reverse d zuerst get()

+1

Ja, es ist so einfach, aber ich bin besonders an der Stream-Lösung interessiert. Vielleicht nicht genau reduce() ist das passende, vielleicht ist es Collectors.joining() oder Collectors.reducing(), aber ich möchte es in einer einzigen Stream-bezogenen Anweisung machen –