关于集合的Java可修改视图

时间:2012-09-05 12:33:14

标签: java data-structures collections

我正在寻求解决以下问题:
从集合A开始,我想将该集合(比如集合B)上的某种“视图”传递给某个方法。视图B不必包含原始集合A的所有元素。如果在此方法中将对象添加到视图(集合B)或从视图中删除,则这些更改也应反映在原始集合A上。

例如(伪代码):

  1. 开始情况:

    Collection A = {1, 2, 3};  
    View-on-collection B = {1, 2};
    
  2. 方法调用:

    someMethod(B) {  
        B.add(4);  
        B.remove(2);  
    }
    
  3. 结束情况:

    Collection A = {1, 3, 4};
    
  4. 有谁知道这个问题的巧妙解决方案?

4 个答案:

答案 0 :(得分:4)

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

public static void main(String[] args) {
    List<Integer> aList = new ArrayList<Integer>(Arrays.asList(1,2,3));
    List<Integer> view = aList.subList(0, 2);

    view.add(new Integer(4));
    view.remove(new Integer(2));
    System.out.println("aList: " + aList);
    System.out.println("view : " + view);        
}

另一种更通用的方法是通过Guavas Collections2.filter(),它允许你定义一个谓词来控制视图中应该有哪些对象:

public static void main(String[] args) {

    List<Integer> aList = new ArrayList<Integer>(Arrays.asList(1,2,3));
    @SuppressWarnings("unchecked")
    Collection<Integer> view = Collections2.filter(aList, new Predicate() {
        public boolean apply(Object arg0) {
            return ((Integer) arg0).intValue() % 3 != 0;
        }});
    view.add(new Integer(4));
    view.remove(new Integer(2));
    System.out.println("aList: " + aList);
    System.out.println("view : " + view);

}

两个例子都打印

aList: [1, 4, 3]
view : [1, 4]

答案 1 :(得分:0)

Jacarta集合框架具有此类功能。但是这个框架不支持泛型。看看谷歌番石榴吧。我相信他们也应该支持这样的功能。

答案 2 :(得分:0)

您可以扩展AbstractList(或者您正在使用的抽象类型的集合)

在这个抽象中,你可以在构造函数中获取源集合,并保存对它的引用以及原始列表视图的起点和终点

覆盖add / remove / set方法,以便也可以对源集合执行这些操作。

class ListView<T> extends AbstractList<T> {

   int start = 0;
   int end = 0;
   private Collection<T> original = null;

   public ListView(List<T> original, int start, int end) {
       this.original = original;
       this.start = start;
       this.end = end;
       super.addAll(0, original.subList(start, end));
   }

   // Any add/set/remove must also alter the original

}

ListView实际上应该是原始列表的Proxy

或者,通过更多工作,您可以实现Collection或List接口,以便以类似的方式直接在原始列表上工作

然后,您可以调用您的方法或像普通集合一样传递ListView。

public void doSomeWork(Collection<String> collection);

...

object.doSomeWork(new ListView<String>(original, 0, 2));

答案 3 :(得分:-2)

您可以始终拥有两个不同的集合,集合A和集合B.

然后,每当您向B添加内容时,都会将其添加到A,每当从B删除某些内容时,您也会将其从A中删除。< / p>

A中删除时,您会检查B是否包含要删除的对象,如果是,则删除它。

但是,添加到A时,您不会触及B

这可能比最佳解决方案的空间效率更低,但它不会改变时间复杂度(除了可能从A删除。)