Модификация HashMap на основе условия с использованием потоков java8 - PullRequest
0 голосов
/ 12 июня 2018

Я хочу создать HashMap<String,Integer> из существующего HashMap<String,Integer>, применив некоторые операции к ключу карты.Предположим, у меня есть строка ->

String sampleString= "SOSSQRSOP";` 

, затем я создал хэш-карту, взяв только 3 символа из строки, как показано ниже (поместив 0 в качестве значения):

Map<String, Integer> messages= new HashMap<>();
messages.put("SOS",0); 
messages.put("SQR",0);
messages.put("SOP",0);

Фактическая задачанайти общее количество различных символов из заданной строки "SOS" с каждым ключом на карте и назначить значение no каждому ключу.Как показано ниже (Конечный результат):

Map<String, Integer> messages= new HashMap<>();
messages.put("SOS",0);
messages.put("SQR",2);
messages.put("SOP",1);

, поэтому я написал код в java8, используя приведенный ниже поток:

    Map<String,Integer>  result= messages
            .entrySet().stream()
            .collect(Collectors.toMap(e-> e.getKey(),
                    e-> e.getKey().stream()
                         .forEach(x-> {
                                if(!"SOS".equals(x)){
                                    char[] characters= {'S','O','S'};
                                    char[] message= x.toCharArray();
                                    for(int i=0; i< characters.length;i++){
                                        int index=0;
                                        if(characters[i] != message[i]){
                                            messages.put(e.getKey(),++index);
                                        }
                                    }
                                }
                            });
                    ));

Я получаю ошибку компиляции.Может кто-нибудь помочь мне написать код с использованием потока.

Отредактировано: Также, пожалуйста, опишите другие подходы, чтобы сделать это.Кстати, в моем случае требовалось создать первое хеш-изображение из заданной строки.

Ответы [ 5 ]

0 голосов
/ 12 июня 2018

Полагаю, у вас есть строка, содержащая все символы.Таким образом, вы можете пропустить создание начальной карты и разбить строку на куски по 3, сопоставив каждую результирующую строку с ключом, и используя некоторую формулу для вычисления diff для значения.

    String sampleString= "SOSSQRSOP";
    final char[] SOS = "SOS".toCharArray();
    Map<String, Integer> result = IntStream.rangeClosed(0, sampleString.length() / 3)
                                           .mapToObj(i -> sampleString.substring(3*i, Math.min(3*i+3, sampleString.length())))
                                           .filter(s -> !s.isEmpty())
                                           .collect(Collectors.toMap(s -> s,
                                                                     s -> (int) IntStream.range(0, s.length())
                                                                                         .filter(i -> SOS[i] != s.charAt(i))  
                                                                                         .count()));

    result.forEach((k,v) -> System.out.println(k + " -> " + v));

Относительно вашегособственная реализация:

for(int i=0; i< characters.length;i++){
   int index=0; //<-- this will always set the index to 0
   if(characters[i] != message[i]){
     messages.put(e.getKey(),++index); //<-- this sets the index to one before assigning it to the map entry value, resulting in being 1, always
   }
}
0 голосов
/ 12 июня 2018

Вы делаете это: e.getKey().stream(), что означает, что вы пытаетесь выполнить потоковую передачу по одному значению, поскольку ваш ключ является строкой, а это невозможно.

Вы можете сделать e.getKey().chars().forEach(...);, и вы получите ожидаемый результат, или вы можете, или e.codePoints().forEach(...).

Если вы используете один из вышеперечисленных методов, вам также нужно будет привести записи кchars, потому что codePoints() и chars() возвращают IntStreams.

Как упоминалось в комментарии @Holger, мой первый ответ содержал следующий фрагмент Stream.of(e.getKey().toCharArray()), который даст вам поток с одним char[].

Определенно, есть лучшие способы сделать то, что вы хотите сделать, но ваш вопрос был об ошибке компиляции.

0 голосов
/ 12 июня 2018

Лучшее, что вы можете сделать для IMO, это вообще не использовать Stream s, а replaceAll:

Map<String, Integer> messages = new HashMap<>();
// sample entries
messages.put("SOS", 0);
messages.put("SQR", 0);
messages.put("SOP", 0);

messages.replaceAll((k, v) -> {
    // calculate new value for each entry
    int diff = 0;
    for (int i = 0; i < "SOS".length(); i++) {
        if ("SOS".charAt(i) != k.charAt(i)) {
            diff++;
        }
    }
    return diff;
});
System.out.println(messages);

Выход

{SQR = 2, SOP =1, SOS = 0}

0 голосов
/ 12 июня 2018

Нет необходимости готовить HashMap.Сборщик потока toMap сделает это за вас:

import static java.util.stream.Collectors.toMap;

Map<String, Integer> result = Stream.of("SOS", "SQR", "SOP")
        .collect(toMap(
                s -> s,
                s -> (int) IntStream.range(0, 3)
                        .filter(i -> "SOS".charAt(i) != s.charAt(i))  // assume all words are 3-letters
                        .count()
         ));

Однако, если у вас уже есть карта и вы хотите изменить ее, используйте replaceAll:

messages.replaceAll(
        (s, unused) -> (int) IntStream.range(0, 3)
                .filter(i -> "SOS".charAt(i) != s.charAt(i))
                .count()
);

Если вашЗадача состоит в том, чтобы разбить исходное сообщение и сравнить каждый триплет с первыми 3 символами, вы можете объединить все это в одном выражении потока:

String message = "SOSSQRSOP";
int n = 3;

assert message.length() % n == 0;

Map<String, Integer> messages = IntStream.range(0, message.length() / n)
        .map(i -> i * n) // starting points of the n-grams
        .mapToObj(idx -> message.substring(idx, idx + n))
        .collect(toMap(
                group -> group,
                group -> (int) IntStream.range(0, n)
                        .filter(i -> message.charAt(i) != group.charAt(i))
                        .count()
        ));
0 голосов
/ 12 июня 2018

Нельзя использовать forEach в преобразователе значений, поскольку оно не возвращает значение.

String x = "SOS";
Map<String,Integer> result = messages
        .entrySet().stream()
        .collect(Collectors.toMap(e-> e.getKey(),
                                  e-> {
                                          int count = 0;
                                          for (int i = 0; i < characters.length; i++){
                                              if (e.getKey().charAt(i) != x.charAt(i)) {
                                                  count++;
                                              }
                                          }
                                          return count;
                                      }));
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...