提问者:小点点

guava-迭代表避免多次迭代


我有一个包含两个字符串属性的对象列表。

public class A {
    public String a;
    public String b;
}

我想检索两个Sets一个包含属性a和一个b

幼稚的方法是这样长的:

List<A> list = ....
Set<String> listofa = new HashSet<>();
Set<String> listofb = new HashSet<>();
for (A item : list) {
    if (item.a != null) 
        listofa.add(item.a);
    if (item.b != null) 
        listofb.add(item.b);

}

试图在番石榴中以一种功能性的方式完成,我最终采用了这种方法:

Function<String,A> getAFromList = new Function<>() {
    @Nullable
    @Override
    public String apply(@Nullable A input) {
        return input.a;
    }
};

Function<String,A> getBFromList = Function<>() {
    @Nullable
    @Override
    public String apply(@Nullable A input) {
        return input.b;
    }
};

FluentIterable<A> iterables = FluentIterable.from(list);

Set<String> listofAs = ImmutableSet.copyOf(iterables.transform(getAFromList).filter(Predicates.notNull()));

Set<String> listofBs = ImmutableSet.copyOf(iterables.transform(getBFromList).filter(Predicates.notNull()));

然而,通过这种方式,我会在列表上迭代两次。

有什么方法可以避免迭代两次或多次吗?

一般来说,如何以功能性的方式解决这些用例(不仅在番石榴/java中)?


共3个答案

匿名用户

首先,你是在追求优化——但是如果性能是关键,使用常规的java方法而不是番石榴(即你的第一种方法)。看这里。

我认为因为你想要两个结果,在某些时候你需要迭代两次(除非你传入要填充的集合之一,但这绝对不是fp方法,因为它不是纯函数)。

但是,如果迭代成本高到需要优化,您可以将其迭代一次到中间结构:

a_b_pairs = transformToJustAB(input) //single expensive iteration
list_of_a = transformA(a_b_pairs) //multiple cheaper iterations
list_of_b = transformB(a_b_pairs)

匿名用户

所以简单的答案是你必须迭代两次。想想看。如果你的List中有N元素,你需要在第一个Set中进行N插入,在第二个Set中进行N插入。无论是功能上的还是其他方面的,你都必须迭代N两次,无论是转换(提取)还是插入。

如果您要使用两个List,则会有所不同,因为您可以创建视图并且仅根据需要进行迭代。

匿名用户

这可以使用Multimaps. index在一次迭代中解决:

    Function<A, String> filterAB = new Function<A, String>() {
        @Override
        public String apply(A input) {

            if (input.a != null) {
                return "a";
            }
            if (input.b != null) {
                return "b";
            }
            return "empty";
        }
    };

    ImmutableListMultimap<String, A> partitionedMap = Multimaps.index(list, filterAB);

输出将是一个Guava Multimap,其中包含三个单独的条目:

  1. 一个不可变列表,其中键“a”下的所有“a-not null”对象。
  2. 一个不可变列表,其中键“b”下的所有“b-not null”对象。
  3. 可能还有一个不可变列表,其中a和b在键“空”下均为空的对象。