【问题标题】:Improving list initialization for n-elements using nested lists使用嵌套列表改进 n 元素的列表初始化
【发布时间】:2021-07-04 12:33:05
【问题描述】:

我想在不使用 for 循环的情况下初始化一个嵌套列表,根列表是: cakeList 将包含另一个,例如(100)。

我的代码:

1. ArrayList<ArrayList<Integer>> cakeList = new ArrayList<>();
2. for (int i=0;i<100;i++) cakeList.add(new ArrayList<>());

我试过了:

import java.util.ArrayList;
public class Solution {
    public static void main(String[] args) {
        ArrayList<ArrayList<Integer>> cakeList = new ArrayList<>(100);
        cakeList.forEach(e-> new ArrayList<>());
        System.out.println(cakeList.size());
        cakeList.get(0);
    }
}

但您可能知道,它符合要求,但在第 7 行抛出错误,因为当我尝试使用 cakeList.get(0) 时 cakeList 为空。

IndexOutOfBoundsException:索引:0,大小:0

提前谢谢你!

【问题讨论】:

  • 第二种方法使用 lamda 将给出 IndexOutOfBoundsException 因为 cakeList 最初是空的。您在尝试第一种方法时是否遇到任何问题?
  • cakeList.forEach(e-&gt; new ArrayList&lt;&gt;()); 这个方法是的会抛出异常,因为 cakeList 是空的。
  • @HeribertoHaydar,cakeList.forEachcakeList 为空时不会抛出IndexOutOfBoundsException,因为这里没有索引。请澄清您的问题。
  • 正如 Alex Rudenko 所说,也不例外,你想在不使用 for 循环的情况下初始化你的 cakeList,例如使用 Stream 吗?
  • @AlexRudenko 我重写了代码。你是对的,因为列表是空的,所以抛出异常。不,因为 ```` cakeList.forEach(e-> new ArrayList() ); ```这段代码。 :)

标签: java performance arraylist


【解决方案1】:

使用Stream::generateStream::limit 创建预定义数量的对象很方便,因此对于二维列表,如下所示:

List<ArrayList<Integer>> list2D = Stream.generate(ArrayList<Integer>::new)
        .limit(100) // Stream<ArrayList<Integer>>
        .collect(Collectors.toList());

list2D.get(0).add(111); // 111 added to one entry

另外,IntStream 可以使用固定范围:

List<ArrayList<Integer>> list2D = IntStream.range(0, 100)
    .mapToObj(i -> new ArrayList<Integer>())
    .collect(Collectors.toList());

如果结果具有特定的ArrayList&lt;ArrayList&gt; 很重要,则可以使用收集器Collectors.toCollection

ArrayList<ArrayList<Integer>> list2D = IntStream.range(0, 100)
    .mapToObj(i -> new ArrayList<Integer>())
    .collect(Collectors.toCollection(ArrayList::new));

还有一个方法Collections.nCopies,但它会创建同一对象的 N 个副本,这可能会产生副作用,即会将一个元素的更改应用于列表中的所有其他“副本”元素。

List<ArrayList<Integer>> cakeList = Collections.nCopies(100, new ArrayList<>());
cakeList.get(0).add(111); // 111 is added to "all" entries in cakeList

【讨论】:

  • 谢谢,我用这个:```` //Create Cakes IntStream.rangeClosed(1,N) .forEach(e->cakeList.add(new ArrayList())); ```
  • @HeribertoHaydar,如果您使用Stream API,则无需使用forEach这种方式修改外部对象。创建所需对象的流(此处:空 ArrayList&lt;Integer&gt;)并将它们收集到 List 或更新中显示的其他集合中。
【解决方案2】:

您的初始化很好,但是初始化后,您的列表都是空的,正如您所期望的docs(请参阅构造函数)。

根据docs 的方法部分,

cakeList.get(0); // "Returns the element at the specified position in this list."

由于您的列表为空,因此指定位置没有元素。 创建非空 ArrayList 的唯一方法是使用构造函数(请参阅docs),它接受一个集合。 示例:

ArrayList<Integer> numbers = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5));
numbers.get(0); //will return 1

您不想使用 for 循环进行初始化的目标是可以理解的,但请参阅post 了解两种方法的速度比较。注意方法调用

cakeList.forEach(e-> new ArrayList<>());

等价于

Iterator<T> iter = cakeList.iterator();
while (iter.hasNext()) {
  iter.next().add(new ArrayList<Integer>();
}

您将得出的结论是填充数组没有捷径,它需要 O(n),其中 n 是您的数组大小。

【讨论】:

  • 谢谢!你是对的..我不担心速度,更重要的是编写++可读代码,减少for循环=)。我正在使用此代码:` //Create Cakes IntStream.rangeClosed(1,N) .forEach(e->cakeList.add(new ArrayList())); `
猜你喜欢
  • 2018-11-06
  • 1970-01-01
  • 1970-01-01
  • 2017-02-27
  • 1970-01-01
  • 2017-11-07
  • 1970-01-01
  • 2021-08-21
  • 1970-01-01
相关资源
最近更新 更多