创建一个基于自定义生成器/迭代器方法的流。

huangapple go评论66阅读模式
英文:

Create a stream that is based on a custom generator/iterator method

问题

如何创建一个基于自定义generate()方法生成一定数量项的流?

这个问题与所引用的问题不同。 最终结果是一个流(Stream),因此我可以(简单地)使用".forEach(System.out::println)"。

一个示例可以是:Stream<String>.generate(myGenerateMethod).forEach(System.out::println);

或者一个简单的示例可以是:

Stream&lt;String&gt; overallStream = Stream.generate(() -> {
    if (generateCounter++ < 5) {
        return "String-" + generateCounter;
    }
    // 关闭流
    return null;
});
overallStream.forEach(System.out::println);

更新和解决方案: 所引用的答案通常不会提供一个流(Stream)。因此,重新打开更好。

maxGenerateCounter = 6;
StreamSupport.stream(Spliterators.spliteratorUnknownSize(new Iterator&lt;String&gt;() {
    int counter = 0;

    @Override
    public boolean hasNext() {
        return counter < maxGenerateCounter;
    }

    @Override
    public String next() {
        // 做一些操作
        // 检查流的“结束”是否已达到
        counter++; // 简单地增加计数器
        if (counter > maxGenerateCounter) {
            return null; // 不重要的答案
        }
        return "String-" + counter;
    }
}, Spliterator.IMMUTABLE), false).forEach(System.out::println);
英文:

How can I create a Stream that creates a number of items based on a custom generate() method?

The question is different from the one referred to. The final result is a Stream, so I could (simplistically) use a ".forach( System.out::println)".

An example would be: Stream<String>.generate( myGenerateMethod).forEach( System.out::println);

Or a simplistic example would be:

Stream&lt;String&gt; overallStream = Stream.generate( () -&gt; {
    if( generateCounter++ &lt; 5) {
        return &quot;String-&quot; + generateCounter;
    }
    // close the stream
    return null; 
});
overallStream.forEach( System.out::println) ;

UPDATE and SOLUTION: referred to answers often don't give a Stream. So reopening was better.

maxGenerateCounter = 6;
StreamSupport.stream(Spliterators.spliteratorUnknownSize(new Iterator&lt;String&gt;() {
	int counter = 0;

	@Override
	public boolean hasNext() {
		return counter &lt; maxGenerateCounter;
	}

	@Override
	public String next() {
		// do something
		// check if the &#39;end&#39; of the Stream is reached
		counter++; // simplistically
		if( counter &gt; maxGenerateCounter) {
			return null; // Not important answer
		}
		return &quot;String-&quot; + counter;
	}
}, Spliterator.IMMUTABLE), false).forEach( System.out::println);

答案1

得分: 2

谢谢,开发者们!!你们激发了我找到解决方案的灵感。非常感谢!

我的问题有点复杂,简化后变得过于简单了。

正如我们可以从许多解决方案中看到的那样,Java和Streams很有趣!

尝试了许多答案后,这个答案有效。它提供了一个相当简单的方法来获取可以轻松控制的流。不需要双重检查标准。我喜欢那些提供洞察力的anyXxx( )答案!

maxGenerateCounter = 6;
System.out.println("使用Splitter: ");
StreamSupport.stream(Spliterators.spliteratorUnknownSize(new Iterator<String>() {
    int counter = 0;
    @Override
    public boolean hasNext() {
        // 简化的解决方案,请参阅下面的解释
        return counter < maxGenerateCounter;
    }
    @Override
    public String next() {
        // 执行操作
        // 提供“停止”流的信息
        counter++; // 为了简单起见
        if (counter > maxGenerateCounter) {
            return null; // 这可以是任何答案。它将被过滤掉。
        }
        return "String-" + counter;
    }
}, Spliterator.IMMUTABLE), false).forEach(System.out::println);

再次感谢贡献者们!

英文:

Thank you, developers!! You inspired me in finding the solution. Many thanks!

My problem was a bit complex, and simplifying let to a over simplified question.

As we can read the many solutions, it looks like Java and Streams is fun to solve!

Experimenting with many answers, this one works. It gives a fairly easy approach of getting a STREAM that easily can be controlled. No double checking of the criteria. I liked those anyXxx( ) answers giving insight!

maxGenerateCounter = 6;
System.out.println( &quot;Using Splitter: &quot;);
StreamSupport.stream(Spliterators.spliteratorUnknownSize(new Iterator&lt;String&gt;() {
    int counter = 0;
    @Override
    public boolean hasNext() {
        // simplistic solution, see below for explanation
        return counter &lt; maxGenerateCounter;
    }
    @Override
    public String next() {
        // executing stuff
        // providing info for &#39;stopping&#39; the stream
        counter++; // for simplicity
        if( counter &gt; maxGenerateCounter) {
           return null; // this could be any answer. It will be filtered out. 
        }
        return &quot;String-&quot; + counter;
    }
}, Spliterator.IMMUTABLE), false).forEach( System.out::println);

Thank you, contributors, again!

答案2

得分: 1

你已经回答了自己的问题。你的代码片段就是如何执行它的。请注意,Stream.generate(lambda) 仅适用于无限流(您不能标记流已结束),因此 Stream.generate 的 javadoc 以以下文本开头:“返回一个__无限__的连续流...”。

然后,您可以使用 limit 来限制它。例如:

AtomicInteger counter = new AtomicInteger();
Stream<String> stream = Stream
    .generate(() -> "String-" + counter.getAndIncrement())
    .limit(5);

请注意,takeWhile 可以很有用,以便您的限制器本身也可以是一个lambda表达式,例如:

AtomicInteger counter = new AtomicInteger();
Stream<String> stream = Stream
    .generate(() -> "String-" + counter.getAndIncrement())
    .takeWhile(count -> count.get() < 5);

takeWhile 不在Java 8中可用(它在Java 11及更高版本中可用)。

另一种选择是创建自己的Spliterator,但这相对较复杂。

第三种选择是创建一个自定义集合,并依赖于其迭代/流能力:

class StringGenerator extends AbstractList<String> {
    private final int size;
    public StringGenerator(int size) { this.size = size; }

    public int size() { return size; }
    public String get(int idx) { return "String-" + idx; }
}

...

new StringGenerator(5).stream().forEach(System.out::println);
英文:

You've answered your own question. Your snippet is exactly how you would do it. Note that Stream.generate(lambda) only works for endless streams (you can't mark that your stream has ended), hence why the javadoc of Stream.generate start with the text: "Returns an infinite sequential...".

You can then use limit to limit this. For example:

AtomicInteger counter = new AtomicInteger();
Stream&lt;String&gt; stream = Stream
    .generate(() -&gt; &quot;String-&quot; + count.getAndIncrement())
    .limit(5)
    ;

Note that takeWhile can be useful so that your limiter can itself also be a lambda, e.g:


AtomicInteger counter = new AtomicInteger();
Stream&lt;String&gt; stream = Stream
    .generate(() -&gt; &quot;String-&quot; + count.getAndIncrement())
    .takeWhile(count.get() &lt; 5)
    ;

but takeWhile isn't in 8 (it is in 11 and up).

Another other alternative is to make your own spliterator but that's rather involved.

A third alternative is to make a custom collection and rely on its iteration/stream abilities:

class StringGenerator extends AbstractList&lt;String&gt; {
    private final int size;
    public StringGenerator(int size) { this.size = size; }

    public int size() { return size; }
    public String get(int idx) { return &quot;String-&quot; + idx; }
}

...

new StringGenerator(5).stream().forEach(System.out::println);

答案3

得分: 1

以下是翻译好的部分:

更加功能化的编写方式是:

IntStream.iterate(0, i -> i < 5, i -> i + 1)
    .mapToObj(i -> "String-" + i)
    .forEach(System.out::println);

从零开始,在i < 5的条件下继续生成元素。在每一步中,加1:i -> i + 1

英文:

The more functional way to write this is:

IntStream.iterate(0, i -&gt; i &lt; 5, i -&gt; i + 1)
    .mapToObj(i -&gt; &quot;String-&quot; + i)
    .forEach(System.out::println);

Start at zero, keep producing elements while i &lt; 5. For each step, add 1: i -&gt; i + 1

huangapple
  • 本文由 发表于 2020年8月12日 21:37:10
  • 转载请务必保留本文链接:https://go.coder-hub.com/63377723.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定