Java 8 extract all keys from matching values in a Map

懵懂的女人 提交于 2021-01-26 03:15:20

问题


I'm relatively new to Java8 and I have a scenario where I need to retrieve all the keys from the Map which matched with the objects.

Wanted to know if there is a way to get all keys without iterating them from the list again.

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()));
}

回答1:


inputMap.entrySet() 
        .stream()
        .filter(entry -> personOutputList.contains(entry.getValue()))
        .map(Entry::getKey)
        .collect(Collectors.toCollection(HashSet::new))



回答2:


Instead of iterating over all the entries of the Map for each Person, I suggest iterating over the Map once:

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

This would still result in quadratic running time (since List.contains() has linear running time). You can improve that to overall linear running time if you create a HashSet containing the elements of personOutputList, since contains for HashSet takes constant time.

You can achieve that by changing

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

to

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



回答3:


You can also use foreach api provided in java8 under lambda's

Below is code for your main method :

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);
            }
        });
    }



回答4:


So, you want a personOutputList with all the selected persons, and a keys set with the keys for those selected persons?

Best (for performance) option is to not discard the keys during search, then split the result into separate person list and key set.

Like this:

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());

The keys set is explicitly made an updatable copy. If you don't need that, drop the copying of the key values:

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


来源:https://stackoverflow.com/questions/49329728/java-8-extract-all-keys-from-matching-values-in-a-map

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!