在Java 8中将数组转换为指定范围的列表

12

我想将一个字符串数组转换为指定范围的列表。在我的情况下,我总是想从索引1到最后一个索引。我不需要包括列表中索引0的值。有没有直接的方法可以过滤并将其转换为我需要的列表?

public class test1 {

    public static void main(String[] args) {
        String[] optArr = {"start", "map1", "map2", "map3"};
        List<String> list = Arrays.stream(optArr).collect(Collectors.toList());
        System.out.println(list);
    }
}

1
ArrayList类有一个subList方法,可以用来切片列表。 - raviraja
1
另外:重命名你的类/变量以遵循适当的命名约定并具有有意义的名称。例如,ArrayToListConversionTest 也是一个更好的名称。 - Naman
基本上,到目前为止所有的答案(除了TongChen的答案)都是浪费时间和空间。(字面意思 - 我的意思是,在这个网站上,以及当它们被实现时)。 想象一下有一个包含1000万个元素的列表,你只想省略第一个元素。创建一个流并将其收集到新列表中的时间和空间复杂度都是O(n)。使用Arrays.asList(optArr).subList(1,optArr.length)的答案是一个优雅、简洁的单行代码,时间和空间复杂度都是O(1)。 - Marco13
9个回答

21

你还可以使用重载的方法 Arrays.stream​(T[] array, int startInclusive, int endExclusive),使用方式如下:

List<String> list = Arrays.stream(optArr, 1, optArr.length)
                          .collect(Collectors.toList());

返回一个顺序流,其源为指定数组的指定范围。


作为另一种选择(非Java-8),使用subList是一种选项,但我更喜欢将其链接在一行中而不是创建一个新对象:

List<String> list = Arrays.asList(optArr).subList(1, optArr.length);

8
asList + subList 的优点是无需分配全新的列表。数组用作列表的后备存储而不是被复制。 - John Kugelman

19
你可以使用 Stream.skip():
List<String> list = Arrays.stream(optArr).skip(1).collect(Collectors.toList());

使用 skip 的唯一挑战是选择初始元素而不是跳过它们。 - Naman
2
@nullpointer 我认为我们都可以安全地同意,在给定的用例中,你的答案是更优秀的。点个赞。 - Robby Cornelissen

4

如果您不使用Java 8,则可以选择在当前列表上创建一个视图,该视图省略第一个元素:

List<String> list = Arrays.stream(optArr).collect(Collectors.toList());
List<String> viewList = list.subList(1, list.size());

这意味着底层数据结构仍然是原始列表,但在内存中多一个元素似乎并不会带来太大的代价。

@nullpointer 嗯...我建议只运行原始流,然后以任何你想要的方式查看它。 - Tim Biegeleisen
为什么要使用流创建一个新的列表,而不是直接使用 Arrays.asList(optArr) - Marco13

3

一种方法是使用List.sublist(int,int)

List<String> list = Arrays.asList(optArr).subList(1,optArr.length);
System.out.println(list);

第二种方法使用Stream
List<String> list = Arrays.stream(optArr)
    .skip(1)
    .collect(Collectors.toList());
System.out.println(list);

第一个可能是最优解。与这里基本上所有其他答案不同,它具有O(1)时间和空间复杂度。 - Marco13

1
查看您的数据,您可能需要考虑:
List<String> list = Stream.of(optArr).filter(s -> s.startsWith("map")).collect(toList());

但是如果您只想过滤第一个索引,sublist 是正确的选择。您不需要在任何地方都使用流。


1

1
应该是这样的。
List<String> al = new ArrayList<>(Arrays.asList(optArr));
List actualList = list.subList(1, al.size());

1
你也可以使用Arrays.copyOfRange来复制一个数组。
将指定的范围从原始数组复制到一个新数组中。范围的初始索引(from)必须在0和original.length之间,包括这两个值。
public static <T> T[] copyOfRange(T[] original, int from, int to)

然后转换为 List
List<String> result = Arrays.asList(Arrays.copyOfRange(optArr, 1, optArr.length));

IntStream:使用IntStream的另一种方式
List<String> result = IntStream.range(1, optArr.length).mapToObj(i->optArr[i]).collect(Collectors.toList());

1
为什么需要使用流?像for-loop这样的古老魔法不能完成任务吗?
String[] optArr = {"start", "map1", "map2", "map3"};
final List<String> list = new ArrayList<>();

for (int i = 1; i < optArr.length; i++) // skip first element
    list.add(optArr[i]);

这是处理任务的最简单工具。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接