Reputation: 180
I implemented this using a loop, but I don't know how do that using a stream. We get two lists for example 1 2 3 and 4 5 6, after mixing the result will be 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;
}
I prepare testing for that. There is 3 tests first - the same size the list second - with one empty list third - with the different size
@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);
}
Any idea how do that on java streams?
Upvotes: 3
Views: 673
Reputation: 311723
One approach could be to use an IntStream
to get a stream of list indices, map them to Optional
s based on whether the list contains this index or not, and then resolve them, although, to be honest, I'm not sure this is more elegant than your original approach:
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();
}
Upvotes: 1
Reputation: 11050
You can use split this into two parts. First you get the min numbers of both lists and mix both lists until this index. After that you append the remaining items in the larger list. To combine both you can use 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());
}
Alternatively you can just use Stream.concat()
while using 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());
}
Upvotes: 1
Reputation: 272370
Here is a solution using streams:
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());
}
}
The magic happens in mapToObj
and flatMap
. It maps every index to a stream of two list elements, one from each list given. And then it flattens the stream of streams with flatMap
.
After that, if the two lists have different sizes, it gets the rest of the longer list and concatenates it to the end.
Upvotes: 1