【问题标题】:List view of concatenated lists串联列表的列表视图
【发布时间】:2018-02-17 13:36:48
【问题描述】:

我想创建一个列表视图,其中包含许多其他列表的串联。

例子:

List<Integer> l1 = Lists.newArrayList(1);
List<Integer> l2 = Lists.newArrayList(2);
List<Integer> l3 = Lists.newArrayList(3);

// This call should not copy any of the argument lists content
List<Integer> concatenation = new ConcatenationListView(l1, l2, l3);

System.out.println(concatenation); // Prints [1, 2, 3]
l3.add(4);
System.out.println(concatenation); // Prints [1, 2, 3, 4]

我可以在 Java 中使用什么样的技术和/或模式来满足这些要求?

详情

  • 我希望串联是惰性的。 (这就是上下文中“视图”的含义。)
  • 我想更改组件列表以反映串联。 (也是“视图”的意思)。
  • 视图不需要是可修改的。
  • 这有点与List.subList 方法相反。
  • 它类似于 Guava Iterables.concat 方法所做的,但我需要一个列表作为结果,而不是一个可迭代的。
  • 我的问题与this one 类似,但我需要List 作为结果级联,而另一个问题的发布者的结果是Iterable

【问题讨论】:

  • “这样的东西是否存在于某处?” 题外话,因为要求我们推荐或查找软件库的问题对于 Stack Overflow 来说是题外话。 --- “或者我如何以最好的方式实现它?”问题是题外话,因为它“太宽泛了”。
  • @Andreas:我认为您的吹毛求疵非常糟糕,但我已经编辑了文本以删除这些短语。我能看到的唯一问题是文本的具体表述。
  • @basst314:不,它不是重复的。在那个问题中,发帖人的结果是Interable。我需要一个List。我将编辑我的问题来解释这一点。

标签: java collections view lazy-evaluation


【解决方案1】:

您可以使用Java8 Stream-API 来处理这个问题。

Stream.of(l1, l2, l3)
    .flatMap(List::stream)
    .forEach(System.out::println);

这将创建三个列表的流,然后通过将每个列表转换为流本身 (List::stream) 并将每个列表中的所有项目连接在一起并将它们平面映射在一起。毕竟它会在控制台上输出每一个元素。

另外:默认情况下流是惰性的,这意味着

只有在发起终端操作时才对源数据进行计算,源元素只在需要时才被消费。

Source

【讨论】:

  • 不,很遗憾,这不起作用。当我将流变成一个渴望的列表时,流创建本身是惰性的。我的整个问题是我需要实现List 接口的东西。
  • @Lii 我发现这个问题已经回答了here。我将问题标记为重复。
  • 不,它不是重复的。在那个问题中,发帖人的结果是Interable。我需要一个List。我将编辑我的问题以解释这一点
  • @Lii 是否可以选择只返回延迟连接的流?这很像一个只读集合。然后,您的调用者可以懒惰地遍历它,对对象做任何他们想做的事情,但不能修改原始集合(“视图”)。这比自己的列表实现要容易得多。
  • 我必须使用第三方 API 来获取列表。另外,出于个人原因,我对此感兴趣。
【解决方案2】:

Java 类库没有这样的组合类,因此您需要自己编写代码。

由于您希望该类允许修改底层列表,因此您不会获得比 O(L) 更好的效率,其中L 是视图管理的列表数量,因为索引转换需要您步行每次需要在特定索引处读取或插入时的列表列表。

另一方面,这使得实现非常简单 - 转换索引的代码如下所示:

class ListView : List<T> {
    private List<List<T>> lists = ...
    public T get(int index) {
        int i = 0;
        while (i != lists.size() && index > lists.get(i).size()) {
            index -= lists.get(i++).size();
        }
        if (i == lists.size()) {
            throw new IndexOutOfBoundsException();
        }
        return lists.get(i).get(index);
    }
    ...
}

【讨论】:

  • class ListView : List&lt;T&gt;?我们要恢复到 C++ 吗? ;-)
  • 感谢您的意见。我怀疑我必须做这样的事情。它可能不会太复杂。我认为扩展AbstractList 是正确的方法。
  • @Andreas:我认为它是伪代码,所以没关系。 :) 从不同标签中的海报得分来看,语法可能受到 C++ 或 C# 的启发...
【解决方案3】:

以下是一个类的实现,它充当多个列表的串联视图。

它并不需要很多行:

/**
 * A list which acts as view of the concatenation of a number of lists.
 */
public class ListConcatenationView<E> extends AbstractList<E> {
    private final List<E>[] lists;

    @SafeVarargs
    public ListConcatenationView(List<E>... lists) {
        this.lists = lists;
    }

    @Override
    public E get(int ix) {
        int localIx = ix;
        for (List<E> l : lists) {
            if (localIx < 0) throw new IndexOutOfBoundsException(ix); 
            if (localIx < l.size()) return l.get(localIx);
            localIx -= l.size();
        }
        return null;
    }

    @Override
    public int size() {
        int size = 0;
        for (List<E> l : lists) {
            size += l.size();
        }
        return size;
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-06-09
    • 1970-01-01
    • 1970-01-01
    • 2012-09-24
    • 1970-01-01
    • 2012-07-24
    • 2016-05-15
    • 1970-01-01
    相关资源
    最近更新 更多