Collections.frequency() 的更高级版本
More advanced version of Collections.frequency()
那么,假设我有以下列表:
List<Foo> myList = getListFromSomePlace();
int frequency = Collections.frequency(myList, someFoo);
这将计算所有 someFoo
个匹配元素。
但是,如果我有一个更"complex"的版本:
List<Foo> myList = getListFromSomePlace();
int frequency = /* get number of Elements in the List whose getInternalFoo() match a certain value */
这样做的一种方法是覆盖 Foo class 中的 equals
方法,但我真的很想避免在 Foo class 中放置自定义行为,特别是因为我可能想根据 Foo class 的不同属性获取频率,而且我只能使用一个版本的覆盖 equals
方法。
像 Collections.sort
这样的函数可以让我传递一个自定义比较器,它可以完全满足我的需要,但是 Collections.frequency 没有提供这个功能。
对于 Java8,我会使用流和一些 Lambda 表达式来解决这个问题,但我想看看是否有一个简单的解决方案适用于 Java 7。我我正在寻找不涉及自己编写自定义频率方法的东西,而是使用一些现有的 API。有什么事吗?
我认为标准 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>
转换为的方法的实用程序 class a 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;
}
我认为您无法避免编写自己的方法。如果您不想污染您的 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;
}
只需 'decorate' 您的 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
.
正如您提到的 'might want to get frequency based on different properties from the Foo class',您可以将匿名内部 class 的 equals()
方法的第一部分移动到通用抽象 class:
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
的子class 来进行比较:
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
}
}
最后,'decorate' 您的 someFoo
使用此子 class 并将 'decorated' 实例传递给 Collections.frequency()
:
List<Foo> myList = getListFromSomePlace();
Foo someFoo = getSomeFooToGetItsFrequency();
int frequency = Collections.frequency(myList, new FooComparingPropertyA(someFoo));
那么,假设我有以下列表:
List<Foo> myList = getListFromSomePlace();
int frequency = Collections.frequency(myList, someFoo);
这将计算所有 someFoo
个匹配元素。
但是,如果我有一个更"complex"的版本:
List<Foo> myList = getListFromSomePlace();
int frequency = /* get number of Elements in the List whose getInternalFoo() match a certain value */
这样做的一种方法是覆盖 Foo class 中的 equals
方法,但我真的很想避免在 Foo class 中放置自定义行为,特别是因为我可能想根据 Foo class 的不同属性获取频率,而且我只能使用一个版本的覆盖 equals
方法。
像 Collections.sort
这样的函数可以让我传递一个自定义比较器,它可以完全满足我的需要,但是 Collections.frequency 没有提供这个功能。
对于 Java8,我会使用流和一些 Lambda 表达式来解决这个问题,但我想看看是否有一个简单的解决方案适用于 Java 7。我我正在寻找不涉及自己编写自定义频率方法的东西,而是使用一些现有的 API。有什么事吗?
我认为标准 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>
转换为的方法的实用程序 class a 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;
}
我认为您无法避免编写自己的方法。如果您不想污染您的 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;
}
只需 'decorate' 您的 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
.
正如您提到的 'might want to get frequency based on different properties from the Foo class',您可以将匿名内部 class 的 equals()
方法的第一部分移动到通用抽象 class:
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
的子class 来进行比较:
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
}
}
最后,'decorate' 您的 someFoo
使用此子 class 并将 'decorated' 实例传递给 Collections.frequency()
:
List<Foo> myList = getListFromSomePlace();
Foo someFoo = getSomeFooToGetItsFrequency();
int frequency = Collections.frequency(myList, new FooComparingPropertyA(someFoo));