让C
成为(部分)由
private static class C {
private final int x;
// lots more fields be here
public C(int x, /* lots more arguments here */) {
this.x = x;
// lots more fields initialized here
}
public int getX(){
return x;
}
}
让cs
成为List<C>
实施RandomAccess
,并按C.getX()
排序。
cs
x1
C.getX()
的{{1}}执行二进制搜索的标准方法是什么? (换句话说,假装每个元素c
被c.getX()
替换,然后我们在这些整数中搜索x1
。)
Collections.binarySearch(
cs,
new C(x1,/* dummy arguments */),
(a,b) -> Integer.compare(a.getX(),b.getX())
);
的缺点是它需要构造一个新的C
(这可能需要大量的伪参数和关于C
的知识)。
Collections.binarySearch(
cs.stream().map(C::getX).collect(Collectors.toList()),
x1
);
的缺点是它创建了一个完整的新列表,大概是O(n)。
有没有办法直接搜索流,而不收集它?或者也许还有其他一些方法来搜索原始列表而不必构建虚拟项目?
如果没有更好的方法,我会这样做:
public class MappedView<T,E> extends AbstractList<E> {
public static <T,E> MappedView<T,E> of(List<T> backingList, Function<T,E> f){
return new MappedView<>(backingList, f);
}
private final List<T> backingList;
private final Function<T,E> f;
private MappedView(List<T> backingList, Function<T,E> f){
this.f = f;
this.backingList = backingList;
}
@Override
public E get(int i) {
return f.apply(backingList.get(i));
}
@Override
public int size() {
return backingList.size();
}
}
然后
Collections.binarySearch(
MappedView.of(cs, c -> c.getX()),
x1
);
答案 0 :(得分:1)
由于您可以控制Comparator
实现,因此可以实现对称比较函数,该函数允许将C
的实例与所需属性的值进行比较,即int
值(在Integer
属性的情况下包装为x
)。有助于了解comparing…
中的工厂方法Comparator
interface,这样可以避免重复比较双方的代码:
int index = Collections.binarySearch(cs, x1,
Comparator.comparingInt(o -> o instanceof C? ((C)o).getX(): (Integer)o));
通过这种方式,您可以搜索int
值x1
,而无需将其包含在C
实例中。
答案 1 :(得分:0)
另一种方法可能是:
private static class C {
private final int x;
// lots more fields be here
private C() {
}
public C(int x, /* lots more arguments here */) {
this.x = x;
// lots more fields initialized here
}
public int getX(){
return x;
}
public static C viewForX(int x) {
C viewInstance = new C();
viewInstance.x = x;
return viewInstance;
}
}
Collections.binarySearch(cs,
C.viewForX(x1),
(a,b) -> Integer.compare(a.getX(),b.getX()));
或者,如果您不介意依赖,可以使用Guava:
执行此操作List<Integer> xs = Lists.transform(cs, C::getX());
Collections.binarySearch(xs, x1);