[英]Equivalent to stream distinct using a custom comparator
如果我有以下列表:
List<String> list = Arrays.asList("hello", "world", "hello");
我應用以下(Java8):
list.stream().distinct().collect(Collectors.toString());
然后我會得到一個“hello”和“world”的列表。
但是,在我的情況下,我有一個類型的列表(從外部api)我想“繞過”等於方法,理想情況下使用比較器,因為它不包括我需要的。
假設這個類看起來像這樣:
public class Point {
float x;
float y;
//getters and setters omitted
}
在這種情況下,我想要將兩個要點定義為相等的標准,例如(30,20)和(30.0001,19.999)。
一個自定義比較器可以做到這一點,但我發現沒有API可以執行Java8 Stream中的distinct(),而是使用比較器(或類似的模式)。
有什么想法嗎? 我知道我可以編寫這樣的函數,但我更喜歡使用現有apis的優雅方式...我對外部庫沒有限制(如果他們有一個舒適的做法,guava,apache-commons等是受歡迎的我需要的)。
HashingStrategy是您正在尋找的概念。 它是一個策略接口,允許您定義equals和hashcode的自定義實現。
public interface HashingStrategy<E>
{
int computeHashCode(E object);
boolean equals(E object1, E object2);
}
Streams不支持散列策略,但Eclipse Collections不支持散列策略。 它具有支持散列策略的集合和映射,以及采用散列策略的distinct()
等方法的重載。
這對字符串很有用。 例如,這是我們如何讓所有不同的字符串忽略大小寫。
MutableList<String> strings = Lists.mutable.with("Hello", "world", "HELLO", "World");
assertThat(
strings.distinct(HashingStrategies.fromFunction(String::toLowerCase)),
is(equalTo(Lists.immutable.with("Hello", "world"))));
或者您可以手動編寫散列策略以避免垃圾創建。
HashingStrategy<String> caseInsensitive = new HashingStrategy<String>()
{
@Override
public int computeHashCode(String string)
{
int hashCode = 0;
for (int i = 0; i < string.length(); i++)
{
hashCode = 31 * hashCode + Character.toLowerCase(string.charAt(i));
}
return hashCode;
}
@Override
public boolean equals(String string1, String string2)
{
return string1.equalsIgnoreCase(string2);
}
};
assertThat(
strings.distinct(caseInsensitive),
is(equalTo(Lists.immutable.with("Hello", "world"))));
這也適用於Points,但前提是您可以將非重疊區域內的所有點分組以具有相同的哈希碼。 如果您使用的比較器定義為當兩個點足夠接近時返回0,則可能會遇到傳遞性問題。 例如,點A,B和C可以沿A線和C線下降,它們都接近B但彼此相距很遠。 盡管如此,如果這對您來說是一個有用的概念,我們歡迎將ListIterable.distinct(Comparator)
添加到API的拉取請求。
注意:我是Eclipse Collections的提交者。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.