Sia C
essere una classe definita (in parte) inCome binario di ricerca su un campo di un elenco elementi
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;
}
}
e lasciare cs
essere un List<C>
attuazione RandomAccess
, e ordinati su C.getX()
.
Quale sarebbe l'approccio standard per eseguire una ricerca binaria in cs
per x1
su C.getX()
? (In altre parole, facendo finta che ciascun elemento c
è sostituito da c.getX()
e poi cercare x1
tra i numeri interi.)
Collections.binarySearch(
cs,
new C(x1,/* dummy arguments */),
(a,b) -> Integer.compare(a.getX(),b.getX())
);
ha l'inconveniente di richiedere la costruzione di un nuovo C
(che può richiedere molti argomenti fittizi e conoscenze su C
).
Collections.binarySearch(
cs.stream().map(C::getX).collect(Collectors.toList()),
x1
);
ha lo svantaggio di creare un'intera nuova lista ed è presumibilmente O (n).
C'è un modo per cercare nello stream direttamente, senza raccoglierlo? O forse un altro modo per cercare l'elenco originale senza dover costruire un oggetto fittizio?
In assenza di un approccio migliore, vorrei fare questo:
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();
}
}
e poi
Collections.binarySearch(
MappedView.of(cs, c -> c.getX()),
x1
);
L'algoritmo di ricerca binaria richiede una conoscenza delle dimensioni della raccolta, che non è qualcosa che può essere facilmente catturata all'interno di un flusso. Quindi hai bisogno di una collezione o di un array. Non credo che ci sia un metodo integrato nel JDK che consente la mappatura durante la ricerca binaria. Quindi il tuo approccio proposto (con MappedView) sembra essere una soluzione ragionevole ed efficiente. A meno che non si possa introdurre qualcosa come 'C.getInstance (x1)' per produrre un oggetto C "fittizio"? – assylias
Dovresti anche implementare 'RandomAccess' sul tuo' MappedView', oppure potrebbe non funzionare correttamente con 'Collections.binarySearch'. In alternativa, puoi usare 'Lists.transform' da Guava, che fa tutto questo per te. –
@LouisWasserman Questa è probabilmente una domanda elementare, ma come potrei garantire che l'argomento 'backingList' implementa sia' List' che 'RandomAccess'? Devo creare una nuova interfaccia per questo? (O c'è già qualcosa come "RandomAccessList"?) – Museful