带密钥提取器的二进制搜索Java列表
假设我有:带密钥提取器的二进制搜索Java列表,java,Java,假设我有: class Item { int id; int type; } 我可以这样做: List<Item> items; Item itemToFind; Comparator<Item> itemComparator; Collections.binarySearch(items, itemToFind, itemComparator); 如果没有额外的开销(例如,将列表转换为列表以调用集合。binarySearch打开或类似)?比较器仍然是比较
class Item {
int id;
int type;
}
我可以这样做:
List<Item> items;
Item itemToFind;
Comparator<Item> itemComparator;
Collections.binarySearch(items, itemToFind, itemComparator);
如果没有额外的开销(例如,将
列表
转换为列表
以调用集合。binarySearch
打开或类似)?比较器仍然是比较器
。您要更改的是比较器的实现,以根据类型而不是id进行计算
Comparator<Item> comparator = new Comparator<Item>(){
public int compare(Item a, Item b)
{
return a.getType() - b.getType();
}
}
在对这个问题进行思考后:
将项目
用作打捆针的替代方法是将比较器
建立在项目
和打捆针机具的接口上
返回int值的接口:
public interface Intgettable{
public int getInt();
}
项
必须实现此接口:
public class Item implements Intgettable{
private int id;
private int type;
public void setId(int id){
this.id = id;
}
public void setType(int type){
this.type = type;
}
public int getId(){
return id;
}
public int getType(){
return type;
}
public int getInt(){
return type;
}
}
搜索键将是一个可创建的Intgettable
:
1-使用扩展Intgettable
的类
public static class MyItemKey implements Intgettable{
private int value;
public MyItemKey(int v){
this.value = v;
}
@Override
public int getInt(){
return value;
}
}
MyItemKey typeToFind = new MyItemKey(6);
2-作为方法内部的匿名类
Intgettable typeTofind = new Intgettable(){
private int value = 6;
public int getInt(){
return value;
}
};
3-或使用lambda版本:
Intgettable typeTofind = ()->{return 6;};
比较器将是:
Comparator<Intgettable> comparator = new Comparator<Intgettable>(){
public int compare(Intgettable a, Intgettable b){
return a.getInt() - b.getInt();
}
};
您的问题是,在集合中
java的二进制搜索实现只允许搜索T
类型的项目。要搜索属于T
的另一种类型,可以执行以下操作:
将另一种类型包装在T
中,在您的情况下,应如下所示:
列表项;
int-typeToFind;
Item itemToFind=新项(/*id*/0的随机值,typeToFind);
int index=binarySearch(items,itemToFind,(a,b)->a.getType()-b.getType());
在此添加一些重要注释:
-项目的比较应该只依赖于并且只依赖于'type',否则您可能会遇到一些讨厌的bug;
-应该对项目列表进行排序。排序应仅取决于且仅取决于“type”(基本上使用与以前相同的比较器)
从初始列表创建新列表:
列表项;
int-typeToFind
int index=binarySearch(items.stream.map(item->item.getType()).collect(Collectors.toList()),itemToFind);
据我所知,Java标准库没有提供二进制搜索实现,其中包含一个用于密钥相等的比较器。如果这些选项不能满足您的要求,您可能应该搜索库或实现自己的搜索。我不明白您为什么要提取类型。您可以编写一个仅比较类型的比较器。二进制搜索将返回您可以从中获取类型的项目。正如埃尔文所说,当您有一个项目列表时,您应该实现一个项目比较器,并将其用于二进制搜索search@ErvinSzilagyi这是binarySearch(列表如果可能的话,你应该将你的typeToFind
包装成一个项
。否则你应该创建一个新的数组。目前提出的解决方案只是需要类技巧的黑客,而我们真正需要的是一个binarySearch
方法,该方法添加一个键提取器作为参数:binarySearch(ListYeah,Item像往常一样有一个getType
getter。如果我没有Item
,但只有它的类型(如问题中的int-typeToFind
),我如何使用上述比较器调用Collections.binarySearch
)当然可以,但实际上是这样的,这一行:Function typeExtractor=Item::getType;
。但是,我不知道你建议我如何调用集合。binarySearch
,你能把它添加到你的答案中吗?我在前面的评论中放的那一行暗示Item
有一个getType
方法。我希望是假定getters和setters在Java中是一个标准的东西,并且被省略了。请假设它们在那里。您更新的答案不是答案-我有几次没有提到我没有Item Item tofind
,但是只有int typeToFind
?仍然需要一个项目,所以您创建了一个项目用作针并设置了它的类型。我添加了一个al用一种物品作为针。
Intgettable typeTofind = ()->{return 6;};
Comparator<Intgettable> comparator = new Comparator<Intgettable>(){
public int compare(Intgettable a, Intgettable b){
return a.getInt() - b.getInt();
}
};
Collections.binarySearch(items, typeToFind, comparator );
List<Item> items;
int typeToFind;
Item itemToFind = new Item(/* random value for id */ 0, typeToFind);
int index = binarySearch(items, itemToFind , (a, b) -> a.getType() - b.getType());
List<Items> items;
int typeToFind
int index = binarySearch(items.stream.map(item -> item.getType()).collect(Collectors.toList()), itemToFind);