Можем ли мы изменить значения карты во время итерации в Java 8 - PullRequest
2 голосов
/ 14 апреля 2020

У меня есть Map<Integer,String>. Мне нужно иметь возможность сначала отфильтровать ключи с четными числами, а затем итерировать значения карты и изменять содержимое значений карты. Я попытался запустить код ниже, но значения не меняются. Возможно ли в java 8 изменить значения на основе некоторого условия при итерации Map?

Map<Integer,String> m = new HashMap<>();
    m.put(1,"ABC");
    m.put(2,"PQR");
    m.put(3,"XYZ");
    m.put(4,"RST");

Map<Integer,String> m1 =  m.entrySet().stream()
    .filter(map -> map.getKey().intValue() %2 == 0)
    .collect(Collectors.toMap(
        map -> map.getKey(),map -> map.getValue()));
            Map<Integer,String> m3 = m1.entrySet().stream()
                .filter(m2 -> {
                    if(m2.getValue().equalsIgnoreCase("PQR")){
                        m2.getValue().replace("PQR","PQR1");
                    } else if(m2.getValue().equalsIgnoreCase("RST")) {
                        m2.getValue().replace("RST", "RST1");
                    }
                    return true;
                }).collect(Collectors.toMap(m2 -> m2.getKey(), m2 -> m2.getValue()));

System.out.println(m3);

Я получаю ответ {2=PQR, 4=RST}, но мой ответ должен быть {2=PQR1, 4=RST1}

Ответы [ 3 ]

1 голос
/ 14 апреля 2020

вы можете сделать все это за один раз, отфильтровать значения, которые вы хотите изменить, и собрать их на новой карте, например:

Map<Integer, String> collect = m.entrySet().stream()
    .filter(e -> e.getKey() % 2 == 0)
    .peek(e -> {
        if (e.getValue().equalsIgnoreCase("PQR")) {
            e.setValue("PQR1");
        }
        if (e.getValue().equalsIgnoreCase("RST")) {
            e.setValue("RST1");
        }
    }).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));

System.out.println(collect);
1 голос
/ 14 апреля 2020

Проблема заключается в методе replace: поскольку строка является неизменной, этот метод возвращает новую строку. Но код игнорирует это возвращаемое значение.

для минимальной адаптации вашего кода создайте карту m3 следующим образом:

    Map<Integer,String> m3 = m1.entrySet().stream().map(m2 -> {
        if(m2.getValue().equalsIgnoreCase("PQR")){
            m2.setValue("PQR1");
        }else if(m2.getValue().equalsIgnoreCase("RST")) {
            m2.setValue("RST1");
        }
        return m2;
    }).collect(Collectors.toMap(m2 -> m2.getKey(), m2 -> m2.getValue()));
0 голосов
/ 14 апреля 2020

Ответ, который я получаю: {2 = PQR, 4 = RST}, но мой ответ должен быть следующим: {2 = PQR1, 4 = RST1}

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

.map(m2 -> new AbstractMap.SimpleEntry<>(m2.getKey(), m2.getValue().replace("PQR","PQR1")))

... или с помощью простого Map::setValue.

Однако, есть гораздо лучше путь. По сути, вы хотите:

  • Отфильтровать эти записи, имеющие определенный value.
  • Изменить эти значения

Stream API предназначен скорее для работы однако с Collection s, чем Map s, они все равно создаются в коллекции. Есть способ, немного неуклюжий, но это:

Map<String, String> helpMap = new HashMap<>();       // the replacement map
helpMap.put("PQR", "PQR1");
helpMap.put("RST", "RST1");

Map<Integer, String> newMap = m.entrySet().stream()
    .filter(map -> map.getKey().intValue() %2 == 0) // only qualified keys
    .map(entry -> new AbstractMap.SimpleEntry<>(
            entry.getKey(),                         // key -> key
            replacementMap.getOrDefault(            // lookup the value in helpMap
                entry.getValue(),                   // ... by the value as key
                entry.getValue())))                 // ... or keep the original value
    .collect(Collectors.toMap(                      // collect back to Map<Integer,String>
            Map.Entry::getKey,                      // ... keys
            Map.Entry::getValue));                  // ... values

Примечания:

  • Решение основано на сопоставлении записей каждой новой Map.Entry с измененными значениями , из которого легко завершить новый Map, используя правильный коллектор.
  • Если значение для замены не найдено в helpMap, то используется исходное значение - это ваше дело. Вы можете отфильтровать эти недопустимые значения, используя .filter(entry -> replacementMap.containsKey(entry.getValue())) перед .map(..).
...