it-swarm.com.ru

Java 8 извлекает все ключи из соответствующих значений на карте

Я относительно новичок в Java8, и у меня есть сценарий, в котором мне нужно получить все ключи с карты, которые соответствуют объектам. 

Хотел узнать, есть ли способ получить все ключи, не повторяя их снова из списка. 

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
Srinivas Lakshman
inputMap.entrySet() 
        .stream()
        .filter(entry -> personOutputList.contains(entry.getValue()))
        .map(Entry::getKey)
        .collect(Collectors.toCollection(HashSet::new))
8
Eugene

Вы также можете использовать foreach api, предоставляемый в Java8 под лямбдами

Ниже приведен код для вашего основного метода: 

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

Вместо того, чтобы перебирать все записи карты для каждой Person, я предлагаю один раз перебрать карту:

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

Это все равно приведет к квадратичному времени работы (так как List.contains() имеет линейное время работы). Вы можете улучшить это до общего линейного времени выполнения, если создадите HashSet, содержащую элементы personOutputList, так как contains для HashSet занимает постоянное время.

Вы можете достичь этого, изменив

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

в

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

Итак, вы хотите personOutputList со всеми выбранными людьми и keys с ключами для этих выбранных людей?

Лучший (для производительности) вариант - не сбрасывать ключи во время поиска, а затем разбивать результат на отдельный список сотрудников и набор ключей.

Как это:

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

Набор keys явно сделан обновляемой копией. Если вам это не нужно, удалите копирование значений ключа:

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