使用流交替混合两个列表

时间:2019-07-12 13:23:03

标签: java collections java-stream

我使用循环来实现这一点,但是我不知道如何使用流来实现。我们得到两个列表,例如1 2 3和4 5 6,混合后的结果将是1 4 2 5 3 6。

public <T> List<T> mixingList(List<T> list1, List<T> list2) {
    List<T> result = new ArrayList<>();

    int maxSize = list1.size() > list2.size() ? list1.size() : list2.size();

    for (int i = 0; i < maxSize; i++) {
        if (i < list1.size()) {
            result.add(list1.get(i));
        }

        if (i < list2.size()) {
            result.add(list2.get(i));
        }
    }

    return result;
}

我为此准备了测试。有3个测试 首先-列表大小相同 第二-有一个空列表 第三-尺寸不同

@Test
public void shouldReturnShakedList() {
    //given
    List<Integer> list1 = new ArrayList<>(Arrays.asList(1, 3, 5));

    List<Integer> list2 = new ArrayList<>(Arrays.asList(2, 4, 6));

    //when
    List<Integer> results = new ShakeListUtil().mixingList(list1, list2);

    //then
    Assertions.assertThat(results).containsExactly(1, 2, 3, 4, 5, 6);
    Assertions.assertThat(results).hasSize(6);
}

@Test
public void shouldReturnJustList2IfList1IsEmpty() {
    //given
    List<Integer> list1 = new ArrayList<>();

    List<Integer> list2 = new ArrayList<>(Arrays.asList(2, 4, 6));

    //when
    List<Integer> results = new ShakeListUtil().mixingList(list1, list2);

    //then
    Assertions.assertThat(results).containsExactly(2, 4, 6);
    Assertions.assertThat(results).hasSize(3);

}

@Test
public void shouldReturnShakedListIfTheSizeListIsDifferent() {
    //given
    List<Integer> list1 = new ArrayList<>(Arrays.asList(1, 3));

    List<Integer> list2 = new ArrayList<>(Arrays.asList(2, 4, 6));

    //when
    List<Integer> results = new ShakeListUtil().mixingList(list1, list2);

    //then
    Assertions.assertThat(results).containsExactly(1, 2, 3, 4, 6);
    Assertions.assertThat(results).hasSize(5);
}

有什么想法在Java流上怎么做?

3 个答案:

答案 0 :(得分:0)

这是使用流的解决方案:

public static <T> List<T> mixingList(List<T> list1, List<T> list2) {
    int shorter = Math.min(list1.size(), list2.size());
    int longer = Math.max(list1.size(), list2.size());
    Stream<T> firstPart = IntStream.range(0, shorter).mapToObj(x -> Stream.of(list1.get(x), list2.get(x))).flatMap(x -> x);
    if (longer > shorter) {
        Stream<T> secondPart = (list1.size() > list2.size() ? list1 : list2).subList(shorter, longer).stream();
        return Stream.concat(firstPart, secondPart).collect(Collectors.toList());
    } else {
        return firstPart.collect(Collectors.toList());
    }
}

魔术发生在mapToObjflatMap中。它将每个索引映射到两个列表元素的流,每个给定列表中的一个。然后,它使用flatMap使流的流变平坦。

此后,如果两个列表的大小不同,它将获取较长列表的其余部分并将其连接到末尾。

答案 1 :(得分:0)

一种方法可能是使用IntStream获取列表索引流,根据列表是否包含该索引将它们映射到Optional,然后解析它们,尽管,老实说,我不确定这是否比您的原始方法还要优雅:

public <T> List<T> mixingList(List<T> list1, List<T> list2) {
    int maxSize = Math.max(list1.size(), list2.size());

    return IntStream.range(0, maxSize)
            .mapToObj(i -> Stream.of(listIndexToOptional(list1, i), 
                                     listIndexToOptional(list2, i)))
            .flatMap(Function.identity())
            .filter(Optional::isPresent)
            .map(Optional::get)
            .collect(Collectors.toList());
}

private static <T> Optional<T> listIndexToOptional(List<T> list, int index) {
    return index < list.size() ? Optional.of(list.get(index)) : Optional.empty();
}

答案 2 :(得分:0)

您可以将其分为两部分。首先,您要获得两个列表的最小值,然后将两个列表混合在一起,直到获得该索引。之后,将其余项目追加到较大的列表中。要将两者结合使用,可以使用Stream.concat()

private static <T> List<T> mixingList(List<T> list1, List<T> list2) {
    int min = Math.min(list1.size(), list2.size());
    return Stream.concat(
            IntStream.range(0, min).boxed()
                    .flatMap(i -> Stream.of(list1.get(i), list2.get(i))),
            (list1.size() < list2.size() ? list2 : list1).stream().skip(min)
    ).collect(Collectors.toList());
}

或者,您可以在使用Stream.concat()的同时使用Stream.flatMap()

private static <T> List<T> mixingList(List<T> list1, List<T> list2) {
    return IntStream.range(0, Math.max(list1.size(), list2.size())).boxed()
            .flatMap(i -> Stream.concat(
                    i < list1.size() ? Stream.of(list1.get(i)) : Stream.empty(),
                    i < list2.size() ? Stream.of(list2.get(i)) : Stream.empty()))
            .collect(Collectors.toList());
}