使用 Guava 将多个 Collection<A> 从 Collection<B> 合并为单个 Collection<A>

Posted

技术标签:

【中文标题】使用 Guava 将多个 Collection<A> 从 Collection<B> 合并为单个 Collection<A>【英文标题】:Merge several Collections<A> into a single Collection<A> from a Collection<B> using Guava 【发布时间】:2012-05-04 19:22:00 【问题描述】:

我想要做的很简单,使用良好的旧循环。

假设我有一个包含 B 列表的对象 A。

public class A

  public List<B> myListOfB;

在其他方法中,我有一个 As 列表。基本上,我想要做的是合并我所有 As 的 B 列表中的所有元素。

例如,使用循环很容易写出这样的东西:

public List<B> someMethod(List<A> myListOfAs)

  List<B> toReturn = new ArrayList<A>();
  for(A myA : myListOfAs)
  
    toReturn.addAll(myA.myListOfB);
  
  return toReturn;

但我想以更实用的方式使用 Guava。这个例子很简单,但它可能会更复杂,例如条件,因此使用函数式编程是有意义的。

我对番石榴很陌生。我已经开始使用它进行过滤和排序,但我很确定它也可以使用它,但我无法弄清楚如何使用它。我找到了这个Combine multiple Collections into a single logical Collection?,但它并没有真正回答我的问题。

【问题讨论】:

你想要的是一种flatten方法。参照。 ***.com/questions/5949091/…. 【参考方案1】:

您可以使用函数来提取列表并使用 concat 来展平列表。这会产生一个 Iterable。

List<A> input;
Function<A, List<B>> t = new Function<A, List<B>>() 
    @Override public List<B> apply(A input)  
        return input.myListOfB; 
    
;
Iterable<B> transform = Iterables.concat(Iterables.transform(input, t));

如果需要,您可以创建一个列表:

ImmutableList<B> asList = ImmutableList.copyOf(transform);
//or
List<B> newArrayList = Lists.newArrayList(transform);

注意:通常,类的公共字段是静态的、不可变的或私有的。其他一切都会给你带来麻烦。

【讨论】:

是的,我正在考虑类似“转换”的东西。这就是我无法理解的意思。非常感谢 !作为静态字段,您是绝对正确的:您应该始终正确封装您的字段。我这样说是为了使示例尽可能简单。【参考方案2】:

如果你让 A 类实现了 Iterable,你可以使用 Iterables.concat()。

public class A
    implements Iterable<B>

    public List<B> myListOfB;

    // from Iterable
    public Iterator<B> iterator ()
    
        return myListOfB.iterator();
    

然后:

List<A> listOfAs = ...;
Iterable<B> allBs = Iterables.concat(listOfAs);

把它放在另一个列表中:

List<B> listOfAllBs = Lists.newArrayList(allBs);

【讨论】:

【参考方案3】:

这个怎么样?我只是粗略地表达了我认为你的意思:

public static void main(String[] args) 

    A a1 = new A();
    a1.bs = Lists.newArrayList(new B("1"), new B("2"), new B("3"));
    A a2 = new A();
    a2.bs = Lists.newArrayList(new B("a"), new B("b"), new B("c"));
    A a3 = new A();
    a3.bs = Lists.newArrayList(new B("!"), new B("@"), new B("#"));

    List<A> as = Lists.newArrayList(a1, a2, a3);
    List<B> lettersAndNumbers = method(as, new Predicate<A>() 
        @Override
        public boolean apply(A input) 
            for (B s : input.bs) 
                if (s.bVal.matches("^[a-zA-Z0-9]*$")) 
                    return true;
                
            

            return false;
        
    );

    System.out.println("as : " + lettersAndNumbers);



static List<B> method(List<A> as, Predicate<A> pred) 
    List<B> newbs = Lists.newArrayList();
    Iterable<A> filtered = Iterables.filter(as, pred);
    for (A a : filtered) 
        newbs.addAll(a.bs);
    

    return newbs;


class A 
    List<B> bs;

    @Override
    public String toString() 
        return "A" + bs.toString() + "";
    


class B 
    String bVal;
    B(String bVal) 
        this.bVal = bVal;
    
    @Override
    public String toString() 
        return "B" + bVal + "";
    

【讨论】:

然而,我的意思是我想避免在主列表中使用循环。在您的示例 method() 中,您创建了一个遍历所有 As 的循环,因此这并不是我真正想要的。但是看看Thomas Jung的回答,我认为它符合我的需要。但无论如何感谢您的时间:)

以上是关于使用 Guava 将多个 Collection<A> 从 Collection<B> 合并为单个 Collection<A>的主要内容,如果未能解决你的问题,请参考以下文章

集合框架学习之Guava Collection

培训日报3.14(mysql,guava,穿山甲等)

Guava中Predicate的常见用法

Guava:为啥没有 Lists.filter() 函数?

guava学习--FunctionPredicate

有没有一种优雅的方法可以在使用 Guava 转换集合时删除空值?