我需要合并两个列表,每个列表中的N个元素交替:从第一个列表中取出前N个元素,从第二个列表中取出前N个元素,在第一个列表中的N个元素的第二部分之后,从N个元素中取出第二部分从第二个清单等。如果一个列表比另一个列表长,则将较长列表中的其余元素附加到结果列表中。
例如,第一个列表:1, 2, 3, 4
,
第二个清单:10, 11, 12, 13, 14, 15, 16, 17
合并N = 2
的交替结果为1, 2, 10, 11, 3, 4, 12, 13, 14, 15, 16, 17
。
这种合并可以通过以下方式实施:
List<Integer> list1 = Arrays.asList(1, 2, 3, 4);
List<Integer> list2 = Arrays.asList(10, 11, 12, 13, 14, 15, 16, 17);
int alternatingNumber = 2;
List<Integer> mergedList = alternatingMerge(list1, list2, alternatingNumber);
public static <T> List<T> alternatingMerge(List<T> list1, List<T> list2, int alternatingNumber) {
List<T> result = new ArrayList<T>();
int size = Math.max(list1.size(), list2.size());
for (int outerIndex = 0; outerIndex < size; outerIndex += alternatingNumber) {
for (int innerIndex = 0; innerIndex < alternatingNumber; innerIndex++) {
if (outerIndex + innerIndex < list1.size()) result.add(list1.get(outerIndex + innerIndex));
}
for (int innerIndex = 0; innerIndex < alternatingNumber; innerIndex++) {
if (outerIndex + innerIndex < list2.size()) result.add(list2.get(outerIndex + innerIndex));
}
}
return result;
}
用于交替1个元素(alternatingNumber = 1)的类似合并算法描述here,但我需要为任何交替数量实现通用逻辑。
是否有可能以某种方式使用Stream API?
答案 0 :(得分:0)
我使用wrap / process / unwrap模式用((entryIndex / alternateStep),entry)封装每个条目。
包装的元素具有可比性,因此当按照自然顺序对流进行排序时,它们将按其位置(entryIndex / alternateStep)进行排序。
在最后一步中,我已将entires流收集到要返回的List中。
import java.util.Arrays;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;
class Program
{
static <T> List<T> alternateElementsBynStep (List<? extends T> flist, List<? extends T> slist, int n)
{
class Wrapper implements Comparable<Wrapper>
{
int position;
T value;
Wrapper (int position, T value)
{
this.position = position;
this.value = value;
}
T getValue ()
{
return value;
}
@Override
public int compareTo(Wrapper o) {
return Integer.compare(position, o.position);
}
}
Function<List<? extends T>, Stream<? extends Wrapper>> wrap =
seq -> IntStream.range(0, seq.size())
.mapToObj(i -> new Wrapper(i / n, seq.get(i)))
;
return Stream.concat(wrap.apply(flist), wrap.apply(slist))
.sorted()
.map(Wrapper::getValue)
.collect(Collectors.toList())
;
}
public static void main(String[] args)
{
System.out.println(Arrays.toString(alternateElementsBynStep(Arrays.asList(1, 2, 3, 4), Arrays.asList(10, 11, 12, 13, 14, 15, 16, 17), 2).toArray()));
// output: [1, 2, 10, 11, 3, 4, 12, 13, 14, 15, 16, 17]
}
}
答案 1 :(得分:0)
Guava提供了一种方法Streams.zip
,该方法允许一次一个元素地处理两个流。以下代码将此方法应用于交替合并两个列表的情况:
public static <T> Stream<T> streamAlternatingInParts(List<T> first, List<T> second, int partSize) {
Stream<Stream<T>> zipped = zip(partitioning(first, partSize), partitioning(second, partSize));
Stream<T> alternating = zipped.flatMap(Function.identity());
int lengthFirst = first.size();
int lengthSecond = second.size();
if (lengthFirst != lengthSecond) {
if (lengthFirst > lengthSecond) {
return Stream.concat(alternating, first.subList(lengthSecond, lengthFirst).stream());
}
return Stream.concat(alternating, second.subList(lengthFirst, lengthSecond).stream());
}
return alternating;
}
public static <T> Stream<Stream<T>> partitioning(List<T> list, int partSize) {
int end = (list.size() + partSize - 1) / partSize;
return IntStream.range(0, end)
.mapToObj(i -> list.subList(partSize * i, Math.min(partSize * i + partSize, list.size())).stream());
}
public static <T> Stream<T> zip(Stream<T> first, Stream<T> second) {
return zip(() -> StreamSupport.stream(first.spliterator(), false), () -> StreamSupport.stream(second.spliterator(), false));
}
public static <T> Stream<T> zip(Supplier<Stream<T>> first, Supplier<Stream<T>> second) {
return Streams.zip(first.get(), second.get(), Stream::of).flatMap(Function.identity());
}
partioning
根据此answer。
zip
根据answer。
适用于问题中给出的示例:
public static void main(String[] args) {
List<Integer> list1 = Arrays.asList(1, 2, 3, 4);
List<Integer> list2 = Arrays.asList(10, 11, 12, 13, 14, 15, 16, 17);
List<Integer> alternatingInParts = streamAlternatingInParts(list1, list2, 2).collect(Collectors.toList());
System.out.println(Iterables.toString(alternatingInParts));
}
输出为:
[1, 2, 10, 11, 3, 4, 12, 13, 14, 15, 16, 17]
由于streamAlternatingInParts
返回了Stream
,因此可以继续进行流式传输。