那么,让我们想象一下,我有以下列表:
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类的不同属性获得频率,而且只能有一个版本的overriden equals方法。
像Collections.sort这样的函数将允许我传递一个自定义比较器,它将完全满足我的需要,但是Collections.frequency没有提供这种功能。
使用Java8,我会使用一个流和一些Lambda表达式来解决这个问题,但是我想看看是否有一个简单的解决方案可以使用Java 7。我正在寻找的东西不是自己编写自定义频率方法,而是使用一些现有的API。有什么事吗?
发布于 2015-02-24 23:17:13
我不认为标准的JDK提供这一点(Java 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); 如果您仍然认为不值得为此添加第三方库,则仍然可以编写自己的函数接口,而提供将List<T>转换为List<U>的方法的实用程序类提供了要应用的映射。这并不难,而且不会占用那么多代码。
编写自己的实现将允许您在一次传递中完成此操作。
static <T, U> int frequency(Collection<T> coll, Function<? super T, ? extends U> mapper, U criteria) {
Objects.requireNonNull(coll);
Objects.requireNonNull(mapper);
Objects.requireNonNull(criteria);
int frequency = 0;
for(T t : coll) {
if(criteria.equals(mapper.apply(t))) {
frequency++;
}
}
return frequency;
}发布于 2015-02-25 00:05:52
我认为你不能避免写你自己的方法。如果你不想污染你的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;
}发布于 2015-02-25 04:12:59
只需根据您的要求,通过重写someFoo来“装饰”您的equals():
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
}
}最后,使用这个子类“装饰”您的someFoo,并将“修饰”实例传递给Collections.frequency()
List<Foo> myList = getListFromSomePlace();
Foo someFoo = getSomeFooToGetItsFrequency();
int frequency = Collections.frequency(myList, new FooComparingPropertyA(someFoo));https://stackoverflow.com/questions/28708087
复制相似问题