问题
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