我想取一串字符串并将其转换为单词对流.例如:
我有:{“A”,“Apple”,“B”,“Banana”,“C”,“Carrot”}
我想要:{(“A”,“Apple”),(“Apple”,“B”),(“B”,“Banana”),(“Banana”,“C”)}.
这与Zipping几乎相同,如Zipping streams using JDK8 with lambda (java.util.stream.Streams.zip)所述
但是,这会产生:
{(A,Apple),(B,Banana),(C,Carrot)}
以下代码有效,但显然是错误的方法(不是线程安全等):
static String buffered = null;
static void output(String s) {
String result = null;
if (buffered != null) {
result = buffered + "," + s;
} else {
result = null;
}
buffered = s;
System.out.println(result);
}
// *****
Stream<String> testing = Stream.of("A","Apple","B","Banana","C","Carrot");
testing.forEach(s -> {output(s);});
解决方法
如果你:
>不喜欢创建包含流中所有字符串的列表的想法
>不想使用外部库
>喜欢弄脏你的手
然后,您可以使用Java 8低级流构建器StreamSupport和Spliterator创建一种从流中对元素进行分组的方法:
class StreamUtils {
public static<T> Stream<List<T>> sliding(int size,Stream<T> stream) {
return sliding(size,1,stream);
}
public static<T> Stream<List<T>> sliding(int size,int step,Stream<T> stream) {
Spliterator<T> spliterator = stream.spliterator();
long estimateSize;
if (!spliterator.hascharacteristics(Spliterator.SIZED)) {
estimateSize = Long.MAX_VALUE;
} else if (size > spliterator.estimateSize()) {
estimateSize = 0;
} else {
estimateSize = (spliterator.estimateSize() - size) / step + 1;
}
return StreamSupport.stream(
new Spliterators.AbstractSpliterator<List<T>>(estimateSize,spliterator.characteristics()) {
List<T> buffer = new ArrayList<>(size);
@Override
public boolean tryAdvance(Consumer<? super List<T>> consumer) {
while (buffer.size() < size && spliterator.tryAdvance(buffer::add)) {
// nothing to do
}
if (buffer.size() == size) {
List<T> keep = new ArrayList<>(buffer.subList(step,size));
consumer.accept(buffer);
buffer = keep;
return true;
}
return false;
}
},stream.isParallel());
}
}
方法和参数命名的灵感来自他们的Scala对应物.
我们来测试一下:
Stream<String> testing = Stream.of("A","Carrot");
System.out.println(StreamUtils.sliding(2,testing).collect(Collectors.toList()));
[[A,Apple],[Apple,B],[B,Banana],[Banana,C],[C,Carrot]]
不重复元素怎么样:
Stream<String> testing = Stream.of("A",2,Carrot]]
现在有一个无限的流:
StreamUtils.sliding(5,Stream.iterate(0,n -> n + 1))
.limit(5)
.forEach(System.out::println);
[0,3,4] [1,4,5] [2,5,6] [3,6,7] [4,7,8]