[英]How to use binarySearch in Collections?
我有動物類,其中包括:重量和顏色。 在這種情況下,如何使用Collections.binarySearch (使用二進制搜索按所需大小查找某些動物):
public static int searchElement(final List<? extends Animal> list, final int weight) {
return Collections.binarySearch(list, weight...);
}
不幸的是,使用內置函數無法直接基於某個屬性搜索元素。
至少有三個選項可以解決此問題:
第一個可能並不適用於所有情況,並且在某些方面看起來值得懷疑。
第二個很簡單,可能是一個可行的選擇。 但是假設由於集合很大而正在執行二進制搜索,則可能在內存和性能方面帶來一些開銷。
第三種選擇可能是最優雅,最通用的一種。 幸運的是, binarySearch
本身並不那么復雜-僅需幾行代碼-因此,很容易制作出自己的可以接收“密鑰提取Function
”的代碼。
我在以下示例中概述了這些方法:
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.function.Function;
class Animal implements Comparable<Animal>
{
private final int weight;
Animal(int weight)
{
this.weight = weight;
}
public int getWeight()
{
return weight;
}
@Override
public int compareTo(Animal that)
{
return Integer.compare(this.weight, that.weight);
}
}
public class CollectionBinarySearch
{
public static void main(String[] args)
{
List<Animal> animals = new ArrayList<Animal>();
animals.add(new Animal(10));
animals.add(new Animal(40));
animals.add(new Animal(20));
animals.add(new Animal(90));
animals.add(new Animal(290));
animals.add(new Animal(130));
Collections.sort(animals);
System.out.println(searchWithInstance(animals, 90));
System.out.println(searchWithInstance(animals, 50));
System.out.println(searchWithArray(animals, 90));
System.out.println(searchWithArray(animals, 50));
System.out.println(searchWithFunction(animals, Animal::getWeight, 90));
System.out.println(searchWithFunction(animals, Animal::getWeight, 50));
}
public static int searchWithInstance(
final List<? extends Animal> list, final int weight) {
return Collections.binarySearch(list, new Animal(weight));
}
public static int searchWithArray(
final List<? extends Animal> list, final int weight) {
int[] array = list.stream().mapToInt(Animal::getWeight).toArray();
return Arrays.binarySearch(array, weight);
}
// Adapted from Collections#binarySearch
private static <T, K extends Comparable<? super K>> int searchWithFunction(
List<? extends T> list, Function<? super T, K> keyExtractor, K key) {
int low = 0;
int high = list.size()-1;
while (low <= high) {
int mid = (low + high) >>> 1;
T midVal = list.get(mid);
int cmp = keyExtractor.apply(midVal).compareTo(key);
if (cmp < 0)
low = mid + 1;
else if (cmp > 0)
high = mid - 1;
else
return mid; // key found
}
return -(low + 1); // key not found
}
}
您可以將列表懶惰地轉換為所需類型的列表:
class LazyTransform extends AbstractList<Integer> implements RandomAccess {
@Override public Integer get(int index) { return items.get(index).weight(); }
@Override public int size() { return items.size(); }
}
Collections.binarySearch(new LazyTransform(), searchWeight);
轉換是惰性的,因為它將僅轉換要比較的值。
或者,如果您可以使用番石榴的Lists.transform
:
Collections.binarySearch(Lists.transform(animals, Animal::weight), searchWeight);
是的,如果輸入列表是RandomAccess
,則轉換后的列表也是如此。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.