更高级版本的Collections.frequency()

时间:2015-02-24 23:03:37

标签: java collections

所以,让我们假设我有以下列表:

List<Foo> myList = getListFromSomePlace();
int frequency = Collections.frequency(myList, someFoo);

这会计算所有someFoo个匹配元素。

但是,如果我有一个更“复杂”的版本:

List<Foo> myList = getListFromSomePlace();
int frequency = /* get number of Elements in the List whose getInternalFoo() match a certain value */

这样做的一种方法是覆盖Foo类中的equals方法,但我真的想避免在Foo类中放置自定义行为,特别是因为我可能想要根据不同的频率获取频率来自Foo类的属性,我只能有一个版本的覆盖equals方法。

Collections.sort这样的函数可以让我传递一个自定义Comparator,它将完全符合我的需要,但Collections.frequency不提供这个功能。

使用Java8,我会使用一个流和一些Lambda表达式来解决这个问题,但我想看看是否有一个可以与Java 7一起使用的简单解决方案。我正在寻找一些不涉及编码的东西我自己的自定义频率方法,但使用一些现有的API。有东西吗?

3 个答案:

答案 0 :(得分:6)

我认为你不能避免编写自己的方法。如果您不想污染您的API,请将其设为私有。

public static <T> int frequency(Collection<T> c, T o, Comparator<T> comp) {
    int freq = 0;
    for(T e : c) {
        if(o == null ? e == null : comp.compare(o, e) == 0) {
            ++freq;
        }
    }
    return freq;
}

答案 1 :(得分:3)

装饰&#39;根据您的要求覆盖someFooequals()

List<Foo> myList = getListFromSomePlace();
final Foo someFoo = getSomeFooToGetItsFrequency();

int frequency = Collections.frequency(myList, new Foo() {
    @Override
    public boolean equals(Object another) {
        if (another == someFoo) {
            return true;
        }
        if ((another == null) || (someFoo == null)) {
            return false;
        }
        if (another.getClass() != someFoo.getClass()) {
            return false;
        }
        Foo anotherFoo = (Foo) another;

        // Compare someFoo to anotherFoo as you wish here

        return comparisonResult;
    }
});

现在,这是有效的,因为Collections.frequency()实现检查对象参数equals()是否列表中的每个元素而不是相反。如果后者为真,则返回的频率始终为0

正如您所提到的,您可能希望根据Foo类的不同属性获取频率,您可以将匿名内部类的equals()方法的第一部分移动到通用抽象类:

public abstract class ComplexFrequency<T> {

    private final T self;

    public ComplexFrequency(T self) {
        this.self = self;
    }

    @Override
    public boolean equals(Object another) {
        if (another == this.self) {
            return true;
        }
        if ((another == null) || (this.self == null)) {
            return false;
        }
        if (another.getClass() != this.self.getClass()) {
            return false;
        }

        // Let subclasses compare both objects
        return this.equals(this.self, (T) another);
    }

    protected abstract boolean equals(T self, T another);
}

然后,创建一个ComplexFrequency的子类,可以根据需要进行比较:

public class FooComparingPropertyA extends ComplexFrequency<Foo> {

    public FooComparingPropertyA(Foo someFoo) {
        super(someFoo);
    }

    @Override
    protected boolean equals(Foo self, Foo another) {
        // check equality based on propertyA
    }
}

最后,&#39;装饰&#39;您的someFoo使用此子类并通过“装饰”#39;实例到Collections.frequency()

List<Foo> myList = getListFromSomePlace();
Foo someFoo = getSomeFooToGetItsFrequency();

int frequency = Collections.frequency(myList, new FooComparingPropertyA(someFoo));

答案 2 :(得分:2)

我不认为标准的JDK提供了这个(Java&lt; = 7)。如果您想要一个适用于Java 7并且不涉及编码的解决方案,您可以使用Guava及其Lists.transform方法。

它看起来像这样:

List<Foo> myList = getListFromSomePlace();
int frequency = Collections.frequency(Lists.transform(myList, new Function<Foo, MyObject>() {
    @Override
    public MyObject apply(Foo input) {
        return input.getInternalFoo();
    }
}), myCriteria); 

如果您仍然认为不值得为此添加第三方库,您仍然可以编写自己的Function接口,以及提供将List<T>转换为{的方法的实用程序类。 {1}}提供了要应用的映射。它不是很难,也不会占用太多代码。

编写自己的实现将允许您一次性完成此操作。

List<U>