簡體   English   中英

按元素類型拆分列表

[英]Split a list by the type of element

對於下面的代碼段:

List<ParentClass> ls = new ArrayList<ParentClass>();
ls.add(new ChildClass1());
ls.add(new ChildClass2());
ls.add(new ChildClass1());
ls.add(new ChildClass2());
ls.add(new ChildClass2());
ls.add(new ChildClass1());
ls.add(new ChildClass2());

List<ChildClass1> sub1 = new ArrayList<ChildClass1>();
List<ChildClass2> sub2 = new ArrayList<ChildClass2>();
for (ParentClass p : ls) {
    if(p instanceof ChildClass1){
        sub1.add((ChildClass1)p);
    } else {
        sub2.add((ChildClass2)p);
    }
}       

System.out.println(sub1);
System.out.println(sub2);

有一個優雅的方式來獲得sub1和sub2? 我確實嘗試過Guava Collections2.filter()返回Collection“ParentClass”,而我需要Collection“ChildClass1”,任何想法?

Collection<ParentClass> sub1= Collections2.filter(ls, Predicates.instanceOf(ChildClass1.class))

使用Guava和單次傳遞可以執行索引操作:

ImmutableListMultimap<Class<?>, ? extends ParentClass> index = FluentIterable.from(ls)
        .index(Object::getClass);
List<ChildClass1> sub1 = (List<ChildClass1>) index.get(ChildClass1.class);
List<ChildClass2> sub2 = (List<ChildClass2>) index.get(ChildClass2.class);

在Java-8之前,用匿名類替換Object::getClass

ImmutableListMultimap<Class<?>, ? extends ParentClass> index = FluentIterable.from(ls)
        .index(new Function<ParentClass, Class<?>>() {
            @Override
            public Class<?> apply(ParentClass o) {
                return o.getClass();
            }
        });

Stream API等效項如下:

Map<?, List<ParentClass>> map = ls.stream().collect(Collectors.groupingBy(Object::getClass));
List<ChildClass1> sub1 = (List<ChildClass1>) (List<?>)map.get(ChildClass1.class);
List<ChildClass2> sub2 = (List<ChildClass2>) (List<?>)map.get(ChildClass2.class);

不幸的是,未經檢查的演員表仍然是必要的。

我覺得這條線上的東西應該有效

Collection<ChildClass1> sub1 = ls.stream()
                                 .filter (x -> x instanceof ChildClass1)
                                 .map ( x-> (ChildClass1) x)
                                 .collect(Collectors.asList());

“番石榴”的最佳方法如下:

List<ParentClass> ls = ... ;
FluentIterable<ParentClass> it = FluentIterable.from(ls);

List<ChildClass1> sub1 = it.filter(ChildClass1.class).toList();
List<ChildClass2> sub2 = it.filter(ChildClass2.class).toList();

請注意,它會導致兩次不同的迭代(實際上是您調用toList() )。

如果您只需要一次迭代,我擔心到目前為止唯一的解決方案正是您在問題中所寫的內容。

Guava假設如果你要過濾T類型的元素,那么結果你仍然會得到一個T的集合(原始集合的子集合)。 無論如何,它無法推斷Predicates.instanceOf(SubT.class)過濾器會導致安全類型轉換,即使它確實會產生SubT列表。 因此,您需要自己對Collection<ChildClass1>進行顯式轉換。 或者,確切地說 - 首先轉換為原始列表,然后轉換為Collection<ChildClass1>以解決編譯器類型檢查問題。

Collection<ChildClass1> sub1= (Collection<ChildClass1>) (Collection) Collections2.filter(ls, Predicates.instanceOf(ChildClass1.class))

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM