【问题标题】:Get multiple elements from list by indices in constant time在恒定时间内通过索引从列表中获取多个元素
【发布时间】:2017-04-29 10:18:01
【问题描述】:

在恒定时间内通过索引从列表中获取多个元素的最佳方法是什么?

如果我有一个数组:

List<String> list = new ArrayList<>();
list.add("a");
list.add("b");
list.add("c");
list.add("d");
list.add("e");

我有一个带有索引的列表/数组:

List<Integer> indices = new ArrayList<>();
indices.add(0);
indices.add(2);
indices.add(3);

如何在恒定时间内得到 a,c,d? 我需要这样的东西:

List<String> filtered = list.filterByIndex(indices);
filtered.stream().forEach(x -> System.out.print(x));
// output:"acd"

更新: 当然,物品的打印不必在恒定时间内进行,只需收集物品即可。上面打印元素的代码仅用于演示目的。

【问题讨论】:

  • 如果有人对这个问题投了反对票,请留下评论这是什么原因...
  • for (Integer index : indices) { System.out.println(list.get(index)); } ?
  • @JB Nizet 我认为这不会在恒定时间内运行。
  • 它是 O(N),其中 N 是索引列表的大小。你不可能打败它。
  • 把N个元素放在一个列表中至少是O(N),不管你怎么看。

标签: java list collections java-8


【解决方案1】:

我建议:

    List<String> filtered = indices.stream()
            .map(list::get)
            .collect(Collectors.toList());

结果是想要的:

[a, c, d]

假设列表具有恒定时间访问(就像ArrayList 一样),它运行的时间与请求的元素数量成线性关系(indices 的长度),但不会随着列出list。正如在 cmets 中所讨论的,这是我们能做的最好的。

编辑:老实说,我不知道上面的收集步骤是否与收集的元素数量成线性关系。列表容量的扩展可能会花费时间,而且可能不会超过线性时间。如果我们需要确定,我们需要这样收集:

            .collect(Collectors.toCollection(() -> new ArrayList<>(indices.size())));

这确保从一开始就分配了具有适当容量的列表,因此不需要扩展。

【讨论】:

    【解决方案2】:

    创建列表:

    List<String> filtered = new ArrayList<>();
    indices.forEach(index -> filtered.add(list.get(index)));
    
    System.out.println(filtered);
    

    流和地图解决方案

    List<String> filtered = indices.stream()
            .map(index -> list.get(index))
            .collect(Collectors.toList());
    

    如果你只需要字符串,你可以用 StringBuilder 来做

    StringBuilder sb = new StringBuffer();
    indices.forEach(index -> sb.append(list.get(index)));
    
    System.out.println(sb.toString());
    

    【讨论】:

    • 谢谢,但是我的示例代码使用了字符串,因为它很容易演示。我想收集泛型类型。 (对不起,我的错误)
    • 用列表更新了答案
    【解决方案3】:

    你可以这样做:

    IntStream.range(0, list.size())
           .boxed()
           .filter(indices::contains)
           .map(list::get)
           .forEach(System.out::println);
    

    【讨论】:

    • 这将花费列表长度的线性时间,对吧?
    • 我怎么能确定您的代码在恒定时间内运行,并且运行时独立于任何列表的长度?
    • @user1802693 这完全不可能。如果你需要打印 N 个东西,时间至少和 N 成正比。
    • 不需要打印物品。我只需要收集它们。示例代码中的打印仅用于演示目的。
    • 如果你不需要对你得到的N个物品做任何事情,那么什么都不做(即不要得到它们),这将是一个恒定的时间。
    猜你喜欢
    • 1970-01-01
    • 2013-12-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-04-25
    • 1970-01-01
    • 1970-01-01
    • 2019-03-03
    相关资源
    最近更新 更多