2012-09-05 27 views
7

我在寻找解决以下问题的方法:
从集合A开始,我希望将某个'视图'传递给该集合(比如集合B)以某种方法。视图B不需要包含原始集合A的所有元素。如果在此方法中将对象添加到视图(集合B)或从视图中删除(这些更改也应该反映在原始集合A上)。关于集合的Java可修改视图

例如(伪代码):

  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}; 
    

有没有人知道这个问题的整洁解决方案?

+1

如果你什么'B.remove(3);''给3'仅在? –

+0

我会说'subList',但这并不完全符合你的要求(视图看起来从来没有改变大小,即使你添加了东西)。 –

+1

@JoachimSauer:视图可以通过'subList()'改变大小。 – Keppil

回答

-2

你总是可以有两个不同的集合,集合A和集合B.

然后,每当你补上一B,你将它添加到A,每当从B删除的东西,你也将消除它从A

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

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

这可能是空间不到最佳的解决方案有效,但它不会改变时间复杂度(除了从A也许清除。)

+0

上的java文档。为什么我有两个downvotes?我的答案很好。 – eboix

+1

我没有低估它,但我认为它没有回答这个问题。使用两个不相关的集合不是一个视图。重点可能是这两个集合将被用在代码的完全不同的部分,所以手动同步将不可能。 – lbalazscs

+0

@lbalazscs但问题是,你在里面创建一个新的Collection,就像这样。我不提议手动同步。我只是说,在添加方法/删除方法中,你做我在我的答案中所说的。 – eboix

0

Jacarta集合框架具有这样的功能。但是这个框架不支持泛型。看看Google Guava。我相信他们也应该支持这样的功能。

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);   
} 

另一种更普遍的方式是通过番石榴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] 
+0

@Downvoter:谨慎解释? – Keppil

+1

是的,我也发现类似的东西,但问题是subList对我们来说不够灵活:我们可能想要保留原始列表中随机位置的一些元素,例如,在第一和第三的位置 - 我认为我们不会去那里使用subList。 – Ward

+0

把事情弄清楚,我不是downvoter。 – Ward

0

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

在此抽象中,您可以在构造函数中获取源集合并持有对它的引用,以及该视图的开始和结束点原始列表

覆盖添加/使这些行动也对源集合执行的同时移除/ 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到原始列表。

另外,与更多的工作,你可以实现的集合或列表界面,让你在一个类似的方式原来名单上的直接工作

然后,您可以打电话给你的方法或通过周围ListView控件作为你会收集一个正常的。

public void doSomeWork(Collection<String> collection); 

... 

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

为什么这是低调的,它是一个有效和透明的解决方案? –

+0

同样在这里。矿井也被低估了。有人可能会发布一个新的答案,看到所有其他的答案,并希望他的答案在最上面...... – eboix