Конкатенация повторяющейся строки n раз к себе на основе значения из Collectors.groupingBy (K, V) - PullRequest
2 голосов
/ 08 мая 2020

Допустим, у меня есть метод, который находит возможные подстроки в String и возвращает конкретную, которая встречается более одного раза, в противном случае он возвращает -1. Например, для abcdabcd возвращается abcd. Мое текущее решение довольно близко к идеалу, но я хочу вернуть вместо abcd конкатенированное вхождение с результатом abcdabcd на основе значения Collectors.groupingBy, потому что в соответствии с парами Key : Value: "abcd" произошло дважды.

public static String StringPeriods(String str) {

    List<String> substrings = new ArrayList<>();
    for (int i = 0; i < str.length(); i++) {
      for (int j = i + 1; j <= str.length(); j++) {
        substrings.add(str.substring(i, j));
      }
    }

    return substrings.stream()
        .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()))
        .entrySet()
        .stream()
        .filter(stringLongEntry -> stringLongEntry.getValue() > 1)
        .map(Entry::getKey)
        .//magic here
        .findFirst()
        .orElse("-1");
  }

Более того, я бы избегал повторного открытия потока вместо использования метода concat() или другого простого решения. Буду признателен за предложения, как достичь цели.

1 Ответ

3 голосов
/ 08 мая 2020

Вы можете решить вашу проблему в несколько этапов:

// Step 1: group by counting 
Map<String, Long> grouping = substrings.stream()
        .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));

// Step 2: find the max value    
Long maxValue = grouping.entrySet().stream()
        .max(Map.Entry.comparingByValue())
        .get()
        .getValue();

// Step 2: filter the entry which have max value and then max length, 
// In the end repeat your String maxValue time
return grouping.entrySet()
        .stream()
        .filter(entry -> entry.getValue() == maxValue)
        .max(Map.Entry.comparingByKey(Comparator.comparingInt(String::length)))
        .map(entry -> entry.getKey().repeat(maxValue.intValue()))
        .get();

Я вас не понимаю, когда вы используете orElse("-1"), я думаю, что это бесполезно, просто используйте get() в конце, и если вы хотите избежать пустых строк, просто сделайте проверку в начале вашего метода:

if (str.isEmpty()) {
    return "-1";
}

Примечание: я использовал repeat, которые существуют в Java11, если вы используете старую версию, есть много способов повторить строку.


Или, как @ Holger , упомяните, вы сразу используете:

return substrings.stream()
        .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()))
        .entrySet()
        .stream()
        .max(Map.Entry.<String, Long>comparingByValue().thenComparingInt(e -> e.getKey().length()))
        .map(entry -> entry.getKey().repeat(entry.getValue().intValue()))
        .get();
...