Как найти первый повторяющийся символ в строке, используя поток Java 8 без промежуточной операции терминала - PullRequest
0 голосов
/ 25 мая 2018

Я использовал приведенный ниже пример кода только для иллюстрации проблемы с потоковым API Java 8.Я не ожидаю обходного пути для данного кода, но объяснение, почему функция аккумулятора невозможна / предоставлена ​​в Stream.

Я хочу получить первый повторяющийся символ в строке без использования операции промежуточного терминала или общей мутации с использованием Java 8 Stream api.Я могу сделать это с оператором сканирования RxJava без боли. Сканирование / аккумулятор в основном позволяют мне получить предыдущий элемент в потоке, и я смог бы вернуть свой собственный тип в качестве предыдущего элемента из сканирования.Я вижу, что нет никаких возможностей с потоком Java 8, но хотел бы знать, почему? В чем проблема при реализации операции сканирования / накопителя в Stream?

Проблемы с обходным решением для достижения этой цели:

  1. Если я использую терминальную операцию, то все мои входы обрабатываются, что не нужно

  2. Если я использую мутацию, код не можетраспараллелить или принести больше проблем, если кто-то использует stream.parallel.

учитывая - String str = "rtydydret";

output - y - потому что y - первый повторяющийся символ в строке.

Обязательный пример для достижения этой цели: -

List<Character> list = new ArrayList<>();

    for (char charecter : str.toCharArray()) {
        if (list.contains(charecter)) {
            System.out.println(charecter);
            break;
        } else {
            list.add(charecter);
        }
    }

Iтакже не хочу использовать приведенный ниже код, поскольку он использует терминальную операцию, что означает, что он обработал все символы в строке, это плохо.

Map<Character, Long> collect =  "abcsdnvs".chars().mapToObj(i -> (char)i).collect(Collectors.groupingBy(Function.identity(), LinkedHashMap::new, Collectors.counting()));
    collect.forEach( (x,y) -> System.out.println( "Key: " + x + " Val: " + y));

    Optional<Character> firstRepeat = collect.entrySet().stream().filter( (e) -> e.getValue() > 1).map(e -> e.getKey()).findFirst();
    System.out.println("First repeating:" + firstRepeat.orElse(null));

Любое понимание было бы очень полезным.Спасибо.

Ответы [ 3 ]

0 голосов
/ 25 мая 2018

Я вижу, что нет возможности с потоком Java 8, но хотел бы знать, почему?

Я не думаю, что вы можете достичь результата с параллелизмом, потому что вы не можете определить, какой из нихПриходите первым при параллельной обработке, если вы не обработаете все свои символы.(так как вам нужно сравнить индекс всех результатов из параллельных, если таковые имеются, чтобы определить, какой из них идет первым)

Без ограничения готовности к параллельному (не используйте параллельный с этим кодом), вы можете попробовать это:

Set<Integer> filter = new HashSet<>();
OptionalInt c = str.chars().filter(e -> !filter.add(e)).findFirst();

if (c.isPresent()) {
   // You can access your repeated char here
   (char) c.getAsInt();
}
0 голосов
/ 25 мая 2018

Есть несколько способов.Первый (который я бы предложил использовать регулярное выражение):

String input = "abcfra";
Pattern p = Pattern.compile("(\\w)(?=.*\\1)");
Matcher m = p.matcher("input");

if (m.find()) {
     System.out.println(m.group());
}

Второй - это Stream-way из двух циклов:

int index = IntStream.range(0, input.length())
            .filter(x -> IntStream.range(x, input.length())
                    .filter(y -> input.indexOf(x) == input.indexOf(y))
                    .findAny()
                    .isPresent()
            )
            .findFirst()
            .getAsInt();

System.out.println(input.charAt(index));

И третий,что вам, очевидно, не нравится:

 char result = input.chars()
            .collect(
                    () -> new LinkedHashMap<Character, Integer>(),
                    (map, x) -> map.merge((char) x, 1, (oldV, newV) -> oldV + newV),
                    (left, right) -> {
                        for (Entry<Character, Integer> e : right.entrySet()) {
                            left.merge(e.getKey(), e.getValue(), (oldV, newV) -> oldV + newV);
                        }

                    }
            )
            .entrySet()
            .stream()
            .filter(x -> x.getValue() > 1)
            .map(Entry::getKey)
            .findFirst()
            .orElse('?');

Что в основном близко к тому же, что и вы.Просто обратите внимание, что вы пытаетесь решить проблему, которую, вероятно, не нужно решать с самого начала (производительность, проходящая через все входные данные и собирающая до Map).

0 голосов
/ 25 мая 2018

Я вижу, что нет никаких возможностей с потоком Java 8, но хотел бы знать, почему?

Потому что это сделало бы язык, в частности, часть с потоками, и карту / фильтр / сокращениеСложнее, чем сейчас.

И даром, учитывая, что вы можете реализовать это без проблем, без использования потоков.Это компромисс между сложностью языка и удобством, которое он приносит или не приносит.

...