wake-up-neo.com

Java 8 extrahiert alle Schlüssel aus übereinstimmenden Werten in einer Map

Ich bin relativ neu in Java8 und habe ein Szenario, in dem ich alle Schlüssel aus der Map abrufen muss, die mit den Objekten übereinstimmen. 

Wollte wissen, ob es eine Möglichkeit gibt, alle Schlüssel zu erhalten, ohne sie erneut aus der Liste zu wiederholen. 

Person.Java
private String firstName;
private String lastName;
//setters and getters & constructor


MAIN Class.

String inputCriteriaFirstName = "john";   

Map<String, Person> inputMap = new HashMap<>();
Collection<Person> personCollection = inputMap.values();
List<Person> personList = new ArrayList<>(personCollection);
List<Person> personOutputList = personList.stream()
.filter(p -> p.getFirstName().contains(inputCriteriaFirstName ))
.collect(Collectors.toList());


//IS There a BETTER way to DO Below ??

Set<String> keys = new HashSet<>();
for(Person person : personOutputList) {
    keys.addAll(inputMap.entrySet().stream().filter(entry -> Objects.equals(entry.getValue(), person))
        .map(Map.Entry::getKey).collect(Collectors.toSet()));
}
10
inputMap.entrySet() 
        .stream()
        .filter(entry -> personOutputList.contains(entry.getValue()))
        .map(Entry::getKey)
        .collect(Collectors.toCollection(HashSet::new))
8
Eugene

Sie können auch foreach api in Java8 unter Lambda verwenden

Nachfolgend finden Sie den Code für Ihre Hauptmethode: 

public static  void main() {

        String inputCriteriaFirstName = "john";   

        Map<String, Person> inputMap = new HashMap<>();
        Set<String> keys = new HashSet<>();

        inputMap.forEach((key,value) -> {
            if(value.getFirstName().contains(inputCriteriaFirstName)){
                keys.add(key);
            }
        });
    }
6
Sahil Aggarwal

Anstatt alle Einträge der Map für jede Person zu durchlaufen, schlage ich vor, die Map einmal zu durchlaufen:

Set<String> keys =
     inputMap.entrySet()
             .stream()
             .filter(e -> personOutputList.contains(e.getValue()))
             .map(Map.Entry::getKey)
             .collect(Collectors.toCollection(HashSet::new));

Dies würde immer noch zu einer quadratischen Laufzeit führen (da List.contains() eine lineare Laufzeit hat). Sie können die lineare Laufzeit insgesamt verbessern, wenn Sie eine HashSet mit den Elementen von personOutputList erstellen, da contains für HashSet eine konstante Zeit benötigt.

Das können Sie durch Veränderung erreichen

List<Person> personOutputList = 
    personList.stream()
              .filter(p -> p.getFirstName().contains(inputCriteriaFirstName))
              .collect(Collectors.toList());

zu

Set<Person> personOutputSet = 
    personList.stream()
              .filter(p -> p.getFirstName().contains(inputCriteriaFirstName))
              .collect(Collectors.toCollection(HashSet::new));
5
Eran

Sie möchten also ein personOutputList mit allen ausgewählten Personen und ein keys mit den Schlüsseln für diese ausgewählten Personen?

Die beste Option (für die Leistung) besteht darin, die Schlüssel während der Suche nicht zu löschen und das Ergebnis in eine separate Personenliste und einen Schlüsselsatz aufzuteilen.

So was:

String inputCriteriaFirstName = "john";
Map<String, Person> inputMap = new HashMap<>();

Map<String, Person> tempMap = inputMap.entrySet()
        .stream()
        .filter(e -> e.getValue().getFirstName().contains(inputCriteriaFirstName))
        .collect(Collectors.toMap(Entry::getKey, Entry::getValue));
List<Person> personOutputList = new ArrayList<>(tempMap.values());
Set<String> keys = new HashSet<>(tempMap.keySet());

Die keys-Gruppe wird explizit als aktualisierbare Kopie erstellt. Wenn Sie das nicht benötigen, löschen Sie das Kopieren der Schlüsselwerte:

Set<String> keys = tempMap.keySet();
1
Andreas