簡體   English   中英

如何使用 Lambda 和 Streams 反轉 Java 8 中的單個字符串?

[英]How can I reverse a single String in Java 8 using Lambda and Streams?

我有一個字符串說"Aniruddh" ,我想在 Java 中使用 lambda 和流來反轉它 8. 我該怎么做?

給定一個字符串

String str = "Aniruddh";

規范的解決方案是

String reversed = new StringBuilder(str).reverse().toString();

如果,也許出於教育目的,您想通過流式傳輸字符串的字符來解決此問題,您可以這樣做

String reversed = str.chars()
    .mapToObj(c -> (char)c)
    .reduce("", (s,c) -> c+s, (s1,s2) -> s2+s1);

這不僅要復雜得多,而且還有很多性能缺陷。

以下解決方案消除了與拳擊相關的開銷

String reversed = str.chars()
    .collect(StringBuilder::new, (b,c) -> b.insert(0,(char)c), (b1,b2) -> b1.insert(0, b2))
    .toString();

但效率仍然較低,因為插入基於數組的緩沖區的開頭意味着復制所有先前收集的數據。

所以底線是,對於實際應用程序,保持在開頭顯示的規范解決方案。

嘗試使用 lambda 和流反轉字符串

import java.util.stream.Stream;
import java.util.stream.Collectors;

    public class Test  {


        public static void main(String[] args) {

            System.out.println(reverse("Anirudh"));;
        }
        public static String reverse(String string) {
            return Stream.of(string)
                .map(word->new StringBuilder(word).reverse())
                .collect(Collectors.joining(" "));
        }
    }

如果你真的想為了學習而這樣做,為什么不反轉 char 數組呢?

public static String reverse(String test) {
    return IntStream.range(0, test.length())
            .map(i -> test.charAt(test.length() - i - 1))
            .collect(StringBuilder::new, (sb, c) -> sb.append((char) c), StringBuilder::append)
            .toString();
}

另一種反轉字符串的方法。 您可以使用 IntStream 從char數組中提取正確的字符。

public static void main(String[] args) {
    char[] charArray = "Aniruddh".toCharArray();
    IntStream.range(0, charArray.length)
        .mapToObj(i -> charArray[(charArray.length - 1) - i])
        .forEach(System.out::print);
}

使用流實現您所要求的最簡單方法可能是:

String result = Stream.of("Aniruddh").map(__ -> "hddurinA").findFirst().get();
Function<String, String> reverse = s -> new StringBuilder(s).reverse().toString();

這是另一種方式,看起來效率不高,但會解釋原因:

String s = "blast";
IntStream.range(0, s.length()).           // create index [0 .. s.length - 1] 
   boxed().                               // the next step requires them boxed
   sorted(Collections.reverseOrder()).    // indices in reverse order
   map(i -> String.valueOf(s.charAt(i))). // grab each index's character 
   collect(Collectors.joining());         // join each single-character String into the final String

如果有一種方法可以附加所有字符而不將每個字符轉換為String然后加入它們會更好。 這就是為什么我說它看起來效率不高。

您可以使用以下技術使用 stream 反轉字符串。

String str = "Aniruddh";

Stream.iterate(str.length()-1, n-> n >= 0, n-> n-1)
        .map(input::charAt)
        .forEach(System.out::print);

另一種替代方法是將字符串拆分為字符串數組並在其上使用 reduce()。

Stream.of("Aniruddh".split("")).reduce("", (reversed, character) -> character + reversed);

給定一個長度為 S 的字符串,反轉整個字符串而不反轉其中的單個單詞。 單詞用點分隔。

String str="abcd.efg.qwerty";

String reversed = Arrays.asList(str.split("\\.")).stream().map(m -> new 
StringBuilder(m).reverse().toString()).collect(Collectors.joining("."));

System.out.println(reversed);
String str = "Noorus Khan";
       int len = str.length();
        IntStream.range(0, len)
                .map(i -> len - 1 - i)
                .mapToObj(j->str.charAt(j))
                .forEach(System.out::print);

輸出 :: nahK surooN

以下是使用 Java 8 流 API 反轉輸入字符串str的另一種方法。

String abc = Arrays.asList(str).stream()
    .map(s -> new StringBuilder(s).reverse().toString())
    .collect(Collectors.toList()).get(0);

如果你想用Stream API實現自定義收集器,它會很方便(我將此任務專門視為練習)。

由於這個問題的貢獻者都沒有提到這種可能性,這里簡要說明如何做到這一點。

創建自定義收集器

您可以通過使用 static 方法Collector.of()的版本之一內聯或通過創建實現Collector接口的class來創建自定義收集器。

在此處輸入圖像描述

  • Supplier Supplier<A>旨在提供一個可變容器,用於存儲 stream 的元素。它可以是CollectionStringBuilder或任何其他可變 object。
  • Accumulator BiConsumer<A,T> 定義如何將元素添加到供應商提供的容器中。
  • Combiner BinaryOperator<A> combiner()建立了在並行執行的情況下如何合並兩個容器的規則。
  • Finisher Function<A,R>旨在通過轉換可變容器來產生最終結果。
  • Characteristics允許提供額外的信息,例如Collector.Characteristics.UNORDERED表示收集器不保證在 stream 的源被排序時保留元素的初始順序,這可以提供更好的並行性能。

最小參數集歸結為supplieraccumulatorcombiner ,它們類似於collect()操作的 arguments ,但有一個區別 - of()期望的 combiner 參數(以及combiner()方法的返回類型)是BinaryOperator<A>

實現

第一個收集器背后的想法是使用ArrayDeque作為可變容器,並將代碼點stream 中的每個元素添加到deque的前面。

並行創建的部分任務將導致必須以相反的順序組合多個雙端隊列 因此,在組合器中,左雙端隊列包含更接近源字符串開頭的值)被附加到右雙端隊列包含更接近源字符串末尾的值),而右雙端隊列作為結果。

Finisher 生成代碼點數組int[]並返回基於它的字符串。

Collector<Integer, Deque<Integer>, String>

String source = "abcdefgh";

String reversed = source.codePoints()
    .boxed()
    .collect(Collector.of(
        ArrayDeque::new,
        Deque::addFirst,
        (Deque<Integer> left, Deque<Integer> right) -> { right.addAll(left); return right; },
        (Deque<Integer> deque) -> new String(
            deque.stream().mapToInt(Integer::intValue).toArray(),
            0,
            deque.size())
    ));

第二個收集器使用char[]作為其可變容器,該容器根據源IntStream的索引進行填充。

Combiner通過查看數組中每個position的最大值來合並兩個arrays。

Finisher 使用構造函數new String(char[])生成結果字符串。

Collector<Integer, char[], String>

String reversed = IntStream.range(0, source.length())
    .boxed()
    .collect(Collector.of(
        () -> new char[source.length()],
        (char[] arr, Integer i) -> arr[(source.length() - 1) - i] = source.charAt(i),
        (char[] left, char[] right) -> {
            for (int i = 0; i < left.length; i++) left[i] = (char) Math.max(left[i], right[i]); return left;
        },
        String::new
    ));

Output對於字符串"abcdefgh"

hgfedcba

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM