Including elements from unmodified lists in modified lists in a 2D list with Streams

浪子不回头ぞ 提交于 2019-12-10 09:53:44

问题


I asked this question about doing the same thing with 1D lists, figuring that it would be easy to apply the answers to 2D lists, but it was not.

Basing my code off of Holger's answer, I came up with this solution:

//list is of type ArrayList<List<Integer>>
list.stream()
        .map(l -> Stream.concat(
                l.subList(0, l.size() - 1).stream().map(i -> i - 2),
                Stream.of(l.get(l.size() - 1)).collect(Collectors.toList())
        ))
        .collect(Collectors.toList());

I get the compile-time error Cannot infer type argument(s) for <R> map(Function<? super T,? extends R>), however, when I try this.

How is can I perform this function on a 2D list?

Some example input and output:

[[1, 2, 3, 4], [5, 6, 7, 8]] should output [[-1, 0, 1, 4], [3, 4, 5, 8]]


回答1:


You have a problem with the parenthesis. Change this:

list.stream()
    .map(l -> Stream.concat(
            l.subList(0, l.size() - 1).stream().map(i -> i - 2),
            Stream.of(l.get(l.size() - 1)).collect(Collectors.toList())
    ))
    .collect(Collectors.toList());

To this:

list.stream()
    .map(l -> Stream.concat(
            l.subList(0, l.size() - 1).stream().map(i -> i - 2),
            Stream.of(l.get(l.size() - 1))).collect(Collectors.toList())
    )
    .collect(Collectors.toList());

Indentation is important here, to improve code readability. I would reindent the second snippet as follows:

list.stream()
    .map(l -> Stream.concat(
            l.subList(0, l.size() - 1).stream().map(i -> i - 2),
            Stream.of(l.get(l.size() - 1)))
        .collect(Collectors.toList()))
    .collect(Collectors.toList());

Or even better, I would move the logic that modifies the inner lists to a helper method:

public final class Utility {
    private Utility() { }

    public static List<Integer> modifyAllButLast(List<Integer> list) {
        return Stream.concat(
                l.subList(0, l.size() - 1).stream().map(i -> i - 2),
                Stream.of(l.get(l.size() - 1)))
            .collect(Collectors.toList());
    }
}

And then I would just use this method from the outer stream:

list.stream()
    .map(Utility::modifyAllButLast)
    .collect(Collectors.toList());

Note: there's no need to move the helper method to a new Utility class and you might even let it be a non-static method. In this case, just change the Utility::modifyAllButLast method reference accordingly.




回答2:


Let's fix the errors step by step

Stream#concat concats two streams together, but you concat one is a List<Integer> not a Stream<Integer>.

list.stream().map(l -> Stream.concat(
    l.subList(0, l.size() - 1).stream().map(i -> i - 2),
    Stream.of(l.get(l.size() - 1)).collect(Collectors.toList())
   // it returns List<Integer> ---^
)).collect(Collectors.toList());

THEN we can fix the error by return a Stream as below:

list.stream().map(l -> Stream.concat(
    l.subList(0, l.size() - 1).stream().map(i -> i - 2),
    Stream.of(l.get(l.size() - 1))
)).collect(Collectors.toList());

BUT the result is not as expected. we expected it returns a List<List<Integer>> but it returns a List<Stream<Integer>> instead. we can collecting the concatinated streams to List<Integer> as below:

list.stream().map(main -> 
    Stream.concat(
        main.subList(0, main.size() - 1).stream().map(i -> i - 2),
        Stream.of(main.get(main.size() - 1))           
    ).collect(Collectors.toList())
//   ^--- collecting Stream<Integer> to List<Integer>
).collect(Collectors.toList());

But I think the best way in this case is using List#replaceAll that I have answered in your another question which is more expressiveness and faster since Stream is more heavier than Collector.

list.stream().map(main ->
    main.stream().collect(collectingAndThen(toList(), it -> {
        // v--- replacing all items in list except the last one 
        it.subList(0, it.size() - 1).replaceAll(item -> item - 2);
        return it;
    }))
).collect(Collectors.toList());



回答3:


This might not be the most elegant way to concatenate the two lists, but it will do it.

list.stream()
    .map(integerList -> {
        List<Integer> toReturn = integerList
                .subList(0, integerList.size() - 1)
                .stream()
                .map(i -> i - 2)
                .collect(Collectors.toList());
        toReturn.add(integerList.get(integerList.size() - 1));
        return toReturn;
    })
    .collect(Collectors.toList());


来源:https://stackoverflow.com/questions/44247260/including-elements-from-unmodified-lists-in-modified-lists-in-a-2d-list-with-str

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!