例如:
输入是无限流,可作为地图缩减每一次传递的有限列表使用:
list 1: List<String> : {"a1_5", "c1_91", "b1_43", "b1_76", "a1_68"}
list 2: List<String> : {"c2_3", "b2_19", "c2_29", "a2_45", "b2_53"}我的输出应该是一个由列表输出实例组成的无限流:
List<String> : {"a1_5,a2_45", "c1_91,c2_3", "b1_43,b2_19", "b1_76,b2_53", "a1_68,a2_45"}或者输出可以是:
List<String> : {"c1_91,c2_3", "b1_43,b2_19", "a1_5,a2_45", "b1_76,b2_53"}发布于 2016-02-19 11:21:11
如果问题是关于Java 8流的,可以使用非常复杂的自定义Spliterator来解决,如下所示:
public static <T,K,R> Stream<R> pairs(Stream<T> a, Stream<T> b,
Function<T, K> keyExtractor, BiFunction<T, T, R> merger) {
Map<K, Queue<T>> aMap = new HashMap<>();
Map<K, Queue<T>> bMap = new HashMap<>();
Spliterator<T> aSpltr = a.spliterator();
Spliterator<T> bSpltr = b.spliterator();
Spliterator<R> res = new Spliterators.AbstractSpliterator<R>(Math.min(
aSpltr.estimateSize(), bSpltr.estimateSize()), Spliterator.ORDERED) {
T at, bt;
boolean hasBuffered = false;
R buf;
@Override
public boolean tryAdvance(Consumer<? super R> action) {
if(hasBuffered) {
hasBuffered = false;
action.accept(buf);
return true;
}
while(true) {
if(!aSpltr.tryAdvance(t -> at = t) || !bSpltr.tryAdvance(t -> bt = t))
return false;
K ak = keyExtractor.apply(at);
K bk = keyExtractor.apply(bt);
Queue<T> bq = bMap.get(ak);
boolean found = false;
if(bq != null) {
found = true;
action.accept(merger.apply(at, bq.poll()));
if(bq.isEmpty()) bMap.remove(ak);
} else {
aMap.computeIfAbsent(ak, k -> new ArrayDeque<>()).add(at);
}
Queue<T> aq = aMap.get(bk);
if(aq != null) {
if(found) {
hasBuffered = true;
buf = merger.apply(aq.poll(), bt);
} else {
found = true;
action.accept(merger.apply(aq.poll(), bt));
}
if(aq.isEmpty()) aMap.remove(bk);
} else {
bMap.computeIfAbsent(bk, k -> new ArrayDeque<>()).add(bt);
}
if(found)
return true;
}
}
};
return StreamSupport.stream(res, a.isParallel() || b.isParallel())
.onClose(a::close).onClose(b::close);
}该方法接受两个流(可能是无限的)、键提取器函数(在您的情况下首先需要提取字符)和合并函数(如何将两个元素组合在一起;在您的情况下,使用","连接)。下面是使用示例:
List<String> list1 = Arrays.asList("a1_5", "c1_91", "b1_43", "b1_76", "a1_68");
List<String> list2 = Arrays.asList("c2_3", "b2_19", "c2_29", "a2_45", "b2_53");
pairs(list1.stream(), list2.stream(), s -> s.charAt(0), (a, b) -> a+","+b)
.forEach(System.out::println);输出:
c1_91,c2_3
b1_43,b2_19
a1_5,a2_45
b1_76,b2_53具有实际无限流的可选示例:将来自仅由最后一个数字不同的两个流的随机数对组合在一起:
pairs(new Random().ints(0, 1000).boxed(), new Random().ints(0, 1000).boxed(),
i -> i/10, (a, b) -> a+","+b)
.limit(100)
.forEach(System.out::println);请注意,对于无限流,如果流中有许多未配对元素,则可以拥有OutOfMemoryError。
发布于 2016-02-19 08:06:06
假设这两个列表大小相同,您可以这样做:
public static void main(String[] args) {
List<String> list1 = new ArrayList<String>();
list1.add("a1_5");
list1.add("c1_91");
list1.add("b1_43");
list1.add("b1_76");
list1.add("a1_68");
List<String> list2 = new ArrayList<String>();
list2.add("c2_3");
list2.add("b2_19");
list2.add("c2_29");
list2.add("a2_45");
list2.add("b2_53");
List<String> result = new ArrayList<String>();
for (int i = 0; i < list1.size(); i++) {
result.add(list1.get(i) + "," + list2.get(i));
}
//Printing the results
for (String a : result) {
System.out.println(a);
}
}如果列表可能有不同的大小,我将使用一些基本代码来控制它,如下所示:
public static void main(String[] args) {
List<String> list1 = new ArrayList<String>();
list1.add("a1_5");
list1.add("c1_91");
list1.add("b1_43");
list1.add("b1_76");
list1.add("a1_68");
//New instance
list1.add("a2");
List<String> list2 = new ArrayList<String>();
list2.add("c2_3");
list2.add("b2_19");
list2.add("c2_29");
list2.add("a2_45");
list2.add("b2_53");
List<String> result = new ArrayList<String>();
int aux = 0;
if (list1.size() >= list2.size()) {
aux = list1.size();
} else {
aux = list2.size();
}
for (int i = 0; i < aux; i++) {
if(i == list1.size()){
result.add(null+","+list2.get(i));
}else if(i == list2.size()){
result.add(list1.get(i)+","+null);
}else{
result.add(list1.get(i)+","+list2.get(i));
}
}
//Printing the results
for (String a : result) {
System.out.println(a);
}
}发布于 2016-02-19 12:25:44
假设您讨论Java 8流,列表具有相同的长度,每个元素可以按照您所描述的方式配对,并且您不介意使用附加的lib Javaslang,可以这样做(不过,对于不同大小的列表,可以这样做):
// functional way
static List<String> pairingFun(List<String> list1, List<String> list2,
BiPredicate<String, String> isPair) {
return pairingFun(list1.size(), Stream.empty(), Stream.ofAll(list1), Stream.ofAll(list2).cycle(), isPair)
.toJavaList();
}
// recursive helper function
static Stream<String> pairingFun(int size, Stream<String> acc, Stream<String> stream1, Stream<String> stream2,
BiPredicate<String, String> isPair) {
if (stream1.isEmpty()) {
return acc;
} else {
String elem1 = stream1.head();
Option<String> elem2 = stream2.take(size).find(that -> isPair.test(elem1, that));
return pairingFun(size,
elem2.map(elem -> acc.append(elem1 + "," + elem)).getOrElse(acc),
stream1.tail(),
elem2.isDefined() ? stream2.dropUntil(that -> isPair.test(elem1, that)).tail() : stream2,
isPair);
}
}在理想的情况下,您不会在Java集合和Javaslang集合之间来回转换,而只使用Javaslang集合。这将进一步减少样板。但是,我怀疑您很可能绑定到其他第三方库的API中。
但是,请注意,如果list1包含太多的元素,则使用上面的递归函数可能会产生堆栈溢出。因此,我建议以老办法做这件事:
// imperative way
static List<String> pairingImp(List<String> list1, List<String> list2,
BiPredicate<String, String> isPair) {
int size = list1.size();
List<String> result = new ArrayList<>(size);
Stream<String> stream = Stream.ofAll(list2).cycle();
for (String elem1 : list1) {
Option<String> elem2 = stream.take(size).find(that -> isPair.test(elem1, that));
if (elem2.isDefined()) {
result.add(elem1 + "," + elem2.get());
stream = stream.dropUntil(that -> isPair.test(elem1, that)).tail();
}
}
return result;
}下面是一个测试:
import javaslang.collection.Stream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.function.BiPredicate;
// ...
public static void main(String[] args) {
List<String> list1 = Arrays.asList("a1_5", "c1_91", "b1_43", "b1_76", "a1_68");
List<String> list2 = Arrays.asList("c2_3", "b2_19", "c2_29", "a2_45", "b2_53");
BiPredicate<String, String> isPair = (s1, s2) -> s1.charAt(0) == s2.charAt(0);
// [a1_5,a2_45, c1_91,c2_3, b1_43,b2_19, b1_76,b2_53, a1_68,a2_45]
System.out.println(pairingFun(list1, list2, isPair));
// [a1_5,a2_45, c1_91,c2_3, b1_43,b2_19, b1_76,b2_53, a1_68,a2_45]
System.out.println(pairingImp(list1, list2, isPair));
}因为我们对list2的每个元素迭代list1,所以我们具有二次运行时性能,即O(n^2)。这可以通过使用映射来查找配对候选来进一步改进。我认为最快的解决方案将在O(n * log n)中执行。
免责声明:我是Javaslang的创建者。
https://stackoverflow.com/questions/35499764
复制相似问题