如何使用没有中间终端操作的java 8流在字符串中查找第一个重复出现的字符

时间:2018-05-25 09:26:47

标签: java java-8 java-stream state-monad

  

我仅使用以下示例代码来说明Java 8流API的问题。我不期望给定代码的解决方法,但解释为什么在Stream中不可能/提供累加器功能。

我想在不使用Java 8 Stream api的中间终端操作或共享变异的情况下获取字符串中的第一个重复出现的字符。我可以用RxJava scan operator无痛苦地做到这一点。 扫描/累加器基本上使我能够抓住流中的前一个元素,并且我可以将自己的类型作为扫描中的前一个元素返回。我看到Java 8流没有可能但是想知道为什么?在Stream中实现扫描/累加器操作有什么问题?

解决方法的问题:

  1. 如果我使用终端操作,则处理所有输入,这是不必要的

  2. 如果我使用突变,如果有人使用stream.parallel,则代码无法并行化或带来更多问题。

  3. 给定 - String str =“rtydydret”;

    输出 - 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);
            }
        }
    

    我也不想使用下面的代码,因为它使用终端操作,这意味着它处理了字符串中的所有字符,这很糟糕。

    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 :(得分:1)

  

我看到Java 8流没有可能,但想知道为什么?

因为这会使语言,特别是带有流的部分,以及map / filter / reduce,比现在更复杂。

无所不知,考虑到你可以毫无问题地实现它,而不使用流。这是语言复杂性与其带来或不带来的便利之间的权衡。

答案 1 :(得分:1)

  

我看到Java 8流没有可能,但想知道为什么?

我不认为你可以通过并行来实现结果,因为除非你处理所有的字符,否则你无法确定哪一个在并行处理时首先出现。 (因为你需要比较并行的所有结果的索引,如果有的话,以确定哪一个是第一个)

没有并行就绪限制(不要与此代码并行使用),您可以尝试:

Sub SortByDate()
' Tables to filter Audit_MA_Main - 6 Week Due Date  Column H  Audit_MA_Main[6 Week Due Date] Oldest to Newest
'                   Audit_Inflight - Status Column B  Audit_Inflight[Status] - A-Z
Dim ASortRange As Range, MASortRange As Range
Dim CurrentWorkbook As Workbook, HomeWorksheet As Worksheet, MAInflightSheet As Worksheet, AuditInflightSheet As Worksheet

Set CurrentWorkbook = Workbooks(ActiveWorkbook.Name)
Set HomeWorksheet = CurrentWorkbook.Sheets("Home")
Set AuditInflightSheet = CurrentWorkbook.Sheets("Audit_InFlight")
Set MAInflightSheet = CurrentWorkbook.Sheets("MA_Inflight")

Dim AuditStatusLO As ListObject
Set AuditStatusLO = AuditInflightSheet.ListObjects("Audit_Inflight")
    AuditStatusLO.ListColumns(3).Select        ' Select the Status Column
    AuditStatusLO.ListColumns(3).Sort SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=xlSortNormal

  End Sub

答案 2 :(得分:1)

有两种方法。第一个(我建议使用正则表达式):

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

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

第二个实际上是两个循环的流式方式:

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)。