Niech C
być zdefiniowana klasa (częściowo) przezJak binarne wyszukiwania w jednej dziedzinie elementów listę za
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;
}
}
i niech cs
być List<C>
realizacji RandomAccess
i klasyfikowane na C.getX()
.
Jakie jest standardowe podejście do wykonywania wyszukiwania binarnego w cs
dla x1
na C.getX()
? (Innymi słowy, udając, że każdy element c
zastępuje c.getX()
a następnie szukamy x1
wśród tych liczb.)
Collections.binarySearch(
cs,
new C(x1,/* dummy arguments */),
(a,b) -> Integer.compare(a.getX(),b.getX())
);
ma tę wadę, że wymaga budowy nowej C
(co może wymagać wiele fałszywych argumentów i wiedzy o C
).
Collections.binarySearch(
cs.stream().map(C::getX).collect(Collectors.toList()),
x1
);
ma tę wadę, że tworzy całą nową listę i jest prawdopodobnie O (n).
Czy istnieje możliwość bezpośredniego wyszukiwania w strumieniu, bez jego pobierania? A może w jakiś inny sposób przeszukać oryginalną listę bez konieczności konstruowania fikcyjnego przedmiotu?
Z braku lepszego podejścia, chciałbym to zrobić:
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();
}
}
a następnie
Collections.binarySearch(
MappedView.of(cs, c -> c.getX()),
x1
);
Algorytm wyszukiwania binarnego wymaga znajomości wielkości kolekcji, co nie jest czymś, co można łatwo przechwycić w strumieniu. Potrzebujesz kolekcji lub tablicy. Nie sądzę, że w JDK istnieje wbudowana metoda, która umożliwia mapowanie podczas przeszukiwania binarnego. Tak więc proponowane podejście (z MappedView) wydaje się rozsądnym i skutecznym rozwiązaniem. Jeśli nie możesz wprowadzić czegoś takiego jak 'C.getInstance (x1)', aby wytworzyć "obojętny" obiekt C? – assylias
Powinieneś także zaimplementować 'RandomAccess' na swoim' MappedView' lub może nie działać efektywnie z 'Collections.binarySearch'. Alternatywnie, możesz użyć 'Lists.transform' z Guava, który robi to wszystko dla ciebie. –
@LouisWasserman To prawdopodobnie elementarne pytanie, ale w jaki sposób zapewnić, że argument 'backingList' implementuje zarówno' List', jak i 'RandomAccess'? Czy muszę stworzyć nowy interfejs? (Czy istnieje coś takiego jak "RandomAccessList" już?) – Museful