简体   繁体   English

如何使用 Lambda 和 Streams 反转 Java 8 中的单个字符串?

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

I have one string say "Aniruddh" and I want to reverse it using lambdas and streams in Java 8. How can I do it?我有一个字符串说"Aniruddh" ,我想在 Java 中使用 lambda 和流来反转它 8. 我该怎么做?

Given a string like给定一个字符串

String str = "Aniruddh";

the canonical solution is规范的解决方案是

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

If, perhaps for educational purposes, you want to solve this by streaming over the string's characters, you can do it like如果,也许出于教育目的,您想通过流式传输字符串的字符来解决此问题,您可以这样做

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

This is not only much more complicated, it also has lots of performance drawbacks.这不仅要复杂得多,而且还有很多性能缺陷。

The following solution eliminates boxing related overhead以下解决方案消除了与拳击相关的开销

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

but is still less efficient as inserting into the beginning of an array based buffer implies copying all previously collected data.但效率仍然较低,因为插入基于数组的缓冲区的开头意味着复制所有先前收集的数据。

So the bottom line is, for real applications, stay with the canonical solution shown at the beginning.所以底线是,对于实际应用程序,保持在开头显示的规范解决方案。

Try this for reverse a string using lambda and streams尝试使用 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(" "));
        }
    }

If you really want to do it for learning purposes, why not reverse the char array?如果你真的想为了学习而这样做,为什么不反转 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();
}

Another approach to reversing your String.另一种反转字符串的方法。 You can use an IntStream to pull the correct character out of a char array.您可以使用 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();

Here is another way, doesn't seem super efficient but will explain why:这是另一种方式,看起来效率不高,但会解释原因:

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

It would be better if there was a way to append all the Characters without converting each to String and then joining them.如果有一种方法可以附加所有字符而不将每个字符转换为String然后加入它们会更好。 That's why I said it doesn't seem super efficient.这就是为什么我说它看起来效率不高。

You can use the below technique to reverse a string using stream.您可以使用以下技术使用 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);

Given a String of length S, reverse the whole string without reversing the individual words in it.给定一个长度为 S 的字符串,反转整个字符串而不反转其中的单个单词。 Words are separated by dots.单词用点分隔。

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

output :: nahK surooN输出 :: nahK surooN

Following is another approach to reverse the input String str using Java 8 streams API.以下是使用 Java 8 流 API 反转输入字符串str的另一种方法。

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

A custom collector can be handy if you want to achieve it with Stream API ( I'm treating this task exclusively as an exercise ).如果你想用Stream API实现自定义收集器,它会很方便(我将此任务专门视为练习)。

Since none of the contributors of this question mentioned this possibility, here's a brief description of how to do that.由于这个问题的贡献者都没有提到这种可能性,这里简要说明如何做到这一点。

Creating a Custom Collector创建自定义收集器

You can create a custom collector either inline by using one of the versions of the static method Collector.of() or by creating a class that implements the Collector interface.您可以通过使用 static 方法Collector.of()的版本之一内联或通过创建实现Collector接口的class来创建自定义收集器。

在此处输入图像描述

  • Supplier Supplier<A> is meant to provide a mutable container which store elements of the stream. It could be a Collection , StringBuilder or any other mutable object. Supplier Supplier<A>旨在提供一个可变容器,用于存储 stream 的元素。它可以是CollectionStringBuilder或任何其他可变 object。
  • Accumulator BiConsumer<A,T> defines how to add elements into the container provided by the supplier . Accumulator BiConsumer<A,T> 定义如何将元素添加到供应商提供的容器中。
  • Combiner BinaryOperator<A> combiner() establishes a rule on how to merge two containers in case of parallel execution. Combiner BinaryOperator<A> combiner()建立了在并行执行的情况下如何合并两个容器的规则。
  • Finisher Function<A,R> is meant to produce the final result by transforming the mutable container. Finisher Function<A,R>旨在通过转换可变容器来产生最终结果。
  • Characteristics allows to provide additional information, for instance Collector.Characteristics.UNORDERED signifies that the collector does not guarantee to preserve initial order of elements when the source of the stream is ordered, which can provide better performance in parallel. Characteristics允许提供额外的信息,例如Collector.Characteristics.UNORDERED表示收集器不保证在 stream 的源被排序时保留元素的初始顺序,这可以提供更好的并行性能。

The minimum set of parameters boils down to supplier , accumulator and combiner which resembles the arguments of collect() operation with one difference - combiner argument expected by of() ( as well as the return type of the combiner() method ) is BinaryOperator<A> .最小参数集归结为supplieraccumulatorcombiner ,它们类似于collect()操作的 arguments ,但有一个区别 - of()期望的 combiner 参数(以及combiner()方法的返回类型)是BinaryOperator<A>

Implementations实现

The idea behind the first collector is to use ArrayDeque as a mutable container and add each element from the stream of code points to the front of the deque .第一个收集器背后的想法是使用ArrayDeque作为可变容器,并将代码点stream 中的每个元素添加到deque的前面。

Portions of tasks created in parallel will result into several deques has to be combined in reversed order.并行创建的部分任务将导致必须以相反的顺序组合多个双端队列 Therefore, in the combiner the left deque ( containing values from closer to the start of the source string ) gets appended to the right deque ( containing values from closer to the end of the source string ), and the right deque is being returned as a result.因此,在组合器中,左双端队列包含更接近源字符串开头的值)被附加到右双端队列包含更接近源字符串末尾的值),而右双端队列作为结果。

Finisher produces an array int[] of code point and returns a string based on it. 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())
    ));

The second collector utilizes char[] as its mutable container which is being populated according to the indices of the source IntStream .第二个收集器使用char[]作为其可变容器,该容器根据源IntStream的索引进行填充。

Combiner merges two arrays by peek the largest value for each position of the array. Combiner通过查看数组中每个position的最大值来合并两个arrays。

Finisher utilizes constructor new String(char[]) to generate the resulting string. 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 ( for string "abcdefgh" ) Output对于字符串"abcdefgh"

hgfedcba

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM