Java流:有没有一种方法可以一次迭代两个元素而不是一个?
假设我们有这条小溪Java流:有没有一种方法可以一次迭代两个元素而不是一个?,java,java-8,java-stream,Java,Java 8,Java Stream,假设我们有这条小溪 Stream.of("a", "b", "err1", "c", "d", "err2", "e", "f", "g", "h", "err3", "i", "j"); 我想在一个映射中保存一对相邻的字符串,其中第一个字符串以“err”开头 我想到的是这样的 Map<String, String> map = new HashMap<>(); Stream.of("a", "b", "err1", "c", "d", "err2", "e", "f
Stream.of("a", "b", "err1", "c", "d", "err2", "e", "f", "g", "h", "err3", "i", "j");
我想在一个映射中保存一对相邻的字符串,其中第一个字符串以“err”开头
我想到的是这样的
Map<String, String> map = new HashMap<>();
Stream.of("a", "b", "err1", "c", "d", "err2", "e", "f", "g", "h", "err3", "i", "j")
.reduce((acc, next) -> {
if (acc.startsWith("err"))
map.put(acc,next);
if (next.startsWith("err"))
return next;
else
return "";
});
List<String> list =
Stream.of("a", "b", "err1", "c", "d", "err2", "e", "f", "g", "h", "err3", "i", "j")
.filterFunctionImWonderingIfExist(/*filters couples of elements*/)
.limit(2)
.collect(Collectors.toList());
而不是
<R> Stream<R> map(Function<? super T, ? extends R> mapper);
流映射(函数您可以编写自定义收集器,或者使用更简单的方法在列表索引上进行流式处理:
Map<String, String> result = IntStream.range(0, data.size() - 1)
.filter(i -> data.get(i).startsWith("err"))
.boxed()
.collect(toMap(data::get, i -> data.get(i+1)));
以下是收集器的源代码。它对并行程序很友好,在其他情况下可能会派上用场:
public static <T, V, A, R> Collector<T, ?, R> pairing(BiPredicate<T, T> filter, BiFunction<T, T, V> map, Collector<? super V, A, R> downstream) {
class Pairing {
T left, right;
A middle = downstream.supplier().get();
boolean empty = true;
void add(T t) {
if (empty) {
left = t;
empty = false;
} else if (filter.test(right, t)) {
downstream.accumulator().accept(middle, map.apply(right, t));
}
right = t;
}
Pairing combine(Pairing other) {
if (!other.empty) {
this.add(other.left);
this.middle = downstream.combiner().apply(this.middle, other.middle);
this.right = other.right;
}
return this;
}
R finish() {
return downstream.finisher().apply(middle);
}
}
return Collector.of(Pairing::new, Pairing::add, Pairing::combine, Pairing::finish);
}
公共静态收集器配对(双预测过滤器、双功能映射、收集器您可以为此任务构建自定义
Map<String, String> map =
Stream.of("a", "b", "err1", "c", "d", "err2", "e", "f", "g", "h", "err3", "i", "j")
.collect(MappingErrors.collector());
如果您的输入位于随机访问列表中,事情会变得更容易。通过这种方式,您可以使用良好的旧列表。子列表方法如下:
List<String> list = Arrays.asList("a", "b", "err1", "c", "d", "err2", "e",
"f", "g", "h", "err3", "i", "j");
Map<String, String> map = IntStream.range(0, list.size()-1)
.mapToObj(i -> list.subList(i, i+2))
.filter(l -> l.get(0).startsWith("err"))
.collect(Collectors.toMap(l -> l.get(0), l -> l.get(1)));
List List=Arrays.asList(“a”、“b”、“err1”、“c”、“d”、“err2”、“e”,
“f”、“g”、“h”、“err3”、“i”、“j”);
Map Map=IntStream.range(0,list.size()-1)
.mapToObj(i->list.subList(i,i+2))
.filter(l->l.get(0).startsWith(“err”))
.collect(Collectors.toMap(l->l.get(0),l->l.get(1));
同样的事情也可以用前面提到的StreamEx库(由我编写)以稍微短一点的方式完成:
List<String> list = Arrays.asList("a", "b", "err1", "c", "d", "err2", "e",
"f", "g", "h", "err3", "i", "j");
Map<String, String> map = StreamEx.ofSubLists(list, 2, 1)
.mapToEntry(l -> l.get(0), l -> l.get(1))
.filterKeys(key -> key.startsWith("err"))
.toMap();
List List=Arrays.asList(“a”、“b”、“err1”、“c”、“d”、“err2”、“e”,
“f”、“g”、“h”、“err3”、“i”、“j”);
Map Map=StreamEx.发布者(列表,2,1)
.mapToEntry(l->l.get(0),l->l.get(1))
.filterKeys(key->key.startsWith(“err”))
.toMap();
不过,如果您不希望第三方依赖,那么糟糕的流API解决方案看起来也不错。下面是一个使用现成收集器的简单单行程序:
Stream<String> stream = Stream.of("a", "b", "err1", "c", "d", "err2", "e", "f", "g", "h", "err3", "i", "j");
Map<String, String> map = Arrays.stream(stream
.collect(Collectors.joining(",")).split(",(?=(([^,]*,){2})*[^,]*$)"))
.filter(s -> s.startsWith("err"))
.map(s -> s.split(","))
.collect(Collectors.toMap(a -> a[0], a -> a[1]));
Stream-Stream=Stream.of(“a”、“b”、“err1”、“c”、“d”、“err2”、“e”、“f”、“g”、“h”、“err3”、“i”、“j”);
Map Map=Arrays.stream(stream
.collect(收集器.连接(“,”).split(“,(?=([^,]*,){2})*[^,]*$)”)
.filter(s->s.startsWith(“err”))
.map(s->s.split(“,”)
.collect(Collectors.toMap(a->a[0],a->a[1]);
这里的“诀窍”是首先将所有术语连接到一个字符串中,然后将其拆分为成对的字符串,例如“a,b”
,“err1,c”
,等等。一旦有了成对的流,处理就很简单了。另一种方法是将Collector.of
和List
作为收集成对的结构。
首先收集到列表
:
List collect=Stream.of(“a”、“b”、“err1”、“c”、“d”、“err2”、“e”、“f”、“g”、“h”、“err3”、“i”、“j”)
.收集(
收藏(
LinkedList::新建,
(a、b)->{
如果(b.startsWith(“err”))
a、 增加(新的阵列列表(列表(b));
如果(!a.isEmpty()&&a.getLast().size()==1),则为else
a、 getLast().add(b);
},
(a,b)->{抛出新的UnsupportedOperationException();}
)
);
然后可以将其转换为映射
Map-toMap=collect.stream().filter(l->l.size()==2)
.collect(collector.toMap)(
e->e.get(0),
e->e.get(1))
);
或使用采集器的多功能一体机。采集器然后
Map toMap=Stream.of(“a”、“b”、“err1”、“c”、“d”、“err2”、“e”、“f”、“g”、“h”、“err3”、“i”、“j”)
收集,收集收集,然后收集(
收藏(
LinkedList::新建,
(a、b)->{
如果(b.startsWith(“err”))
a、 增加(新的阵列列表(列表(b));
如果(!a.isEmpty()&&a.getLast().size()==1),则为else
a、 getLast().add(b);
},
(a,b)->{抛出新的UnsupportedOperationException();}
),(x)->x.stream().filter(l->l.size()==2)
.collect(collector.toMap)(
e->e.get(0),
e->e.get(1))
)
));
看起来你需要一个收藏品,我想了想,但是我找不到一个(干净漂亮的)解决方案嗯,在最初的问题中,源流是一个日志文件,因此您实际上没有访问索引的权限。因此,没有更直接的方法。+1对于StreamEx库,非常有趣的项目!PairMap
完美地解决了我的问题needs@LuigiCortese我不这么认为。那很不幸。Scala在Strea上有一个很好的方法M在这里是合适的:它把元素固定在固定大小的块中。我听说过。IMHO这个中间有一个很大的深孔。它可以更复杂,更容易。understandable@LuigiCortese使用pairMap
解决方案,您可以在.filter(Objects::nonNull)之后添加.limit(2*n)
这样它就限制了n对情侣。还有为什么.limit(2*n)
?似乎.limit(n)
是@LuigiCortese想要的。我喜欢StreamEx背后的想法,我希望很快能推出一些有趣的PR=)@LuigiCortese,请注意,我并不急于接受每一个增强。每一个增强都有许多优点和缺点需要评估。例如,我可能会拒绝任何显示出较差并行性能的新功能。可能最好先在坏主意中讨论您的想法。这很容易出错。如果有,
在其中一个输入字符串中,它将执行意外的操作。此外……这个疯狂的正则表达式是关于什么的?:-)
Map<String, String> map =
StreamEx.of("a", "b", "err1", "c", "d", "err2", "e", "f", "g", "h", "err3", "i", "j")
.pairMap((s1, s2) -> s1.startsWith("err") ? new String[] { s1, s2 } : null)
.nonNull()
.toMap(a -> a[0], a -> a[1]);
System.out.println(map);
List<String> list = Arrays.asList("a", "b", "err1", "c", "d", "err2", "e",
"f", "g", "h", "err3", "i", "j");
Map<String, String> map = IntStream.range(0, list.size()-1)
.mapToObj(i -> list.subList(i, i+2))
.filter(l -> l.get(0).startsWith("err"))
.collect(Collectors.toMap(l -> l.get(0), l -> l.get(1)));
List<String> list = Arrays.asList("a", "b", "err1", "c", "d", "err2", "e",
"f", "g", "h", "err3", "i", "j");
Map<String, String> map = StreamEx.ofSubLists(list, 2, 1)
.mapToEntry(l -> l.get(0), l -> l.get(1))
.filterKeys(key -> key.startsWith("err"))
.toMap();
Stream<String> stream = Stream.of("a", "b", "err1", "c", "d", "err2", "e", "f", "g", "h", "err3", "i", "j");
Map<String, String> map = Arrays.stream(stream
.collect(Collectors.joining(",")).split(",(?=(([^,]*,){2})*[^,]*$)"))
.filter(s -> s.startsWith("err"))
.map(s -> s.split(","))
.collect(Collectors.toMap(a -> a[0], a -> a[1]));