使用 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>的主要内容,如果未能解决你的问题,请参考以下文章