Ich habe eine String[]
mit Werten wie diesen:
public static final String[] VALUES = new String[] {"AB","BC","CD","AE"};
Gegeben String s
Gibt es eine gute Methode, um zu testen, ob VALUES
enthält s
?
Ich habe eine String[]
mit Werten wie diesen:
public static final String[] VALUES = new String[] {"AB","BC","CD","AE"};
Gegeben String s
Gibt es eine gute Methode, um zu testen, ob VALUES
enthält s
?
Wenn das Array nicht sortiert ist, müssen Sie alles durchgehen und für jedes Element einen Aufruf von equals durchführen.
Wenn das Array sortiert ist, können Sie eine binäre Suche durchführen, es gibt eine in der Arrays Klasse.
Im Allgemeinen sollten Sie, wenn Sie viele Mitgliedschaftsprüfungen durchführen wollen, alles in einem Set und nicht in einem Array speichern.
Außerdem, wie ich in meiner Antwort sagte, wenn Sie die Arrays-Klasse verwenden, können Sie das Array sortieren und dann die binäre Suche auf dem neu sortierten Array durchführen.
@Thomas: Ich stimme zu. Oder Sie können einfach alles in ein TreeSet hinzufügen; gleiche Komplexität. Ich würde die Arrays verwenden, wenn es sich nicht ändert (vielleicht ein wenig Speicherplatz sparen, da die Referenzen zusammenhängend sind, obwohl die Strings nicht sind). Ich würde die Menge verwenden, wenn dies im Laufe der Zeit ändern würde.
Ich habe einen Test durchgeführt, in dem ich die 3 Vorschläge in Bezug auf die Geschwindigkeit verglichen habe. Ich generierte zufällige Ganzzahlen, konvertierte sie in einen String und fügte sie zu einem Array hinzu. Dann suchte ich nach der höchstmöglichen Zahl/Zeichenkette, die im schlimmsten Fall für die asList().contains()
.
Bei einer Array-Größe von 10K waren die Ergebnisse wie folgt:
Sort & Search : 15
Binary Search : 0
asList.contains : 0
Bei Verwendung eines 100K-Arrays waren die Ergebnisse wie folgt:
Sort & Search : 156
Binary Search : 0
asList.contains : 32
Wenn also das Array in sortierter Reihenfolge erstellt wird, ist die binäre Suche die schnellste, andernfalls die asList().contains
wäre der richtige Weg. Wenn Sie viele Suchanfragen haben, kann es sich lohnen, das Array zu sortieren, damit Sie die binäre Suche verwenden können. Es hängt alles von Ihrer Anwendung ab.
Ich denke, das sind die Ergebnisse, die die meisten Menschen erwarten würden. Hier ist der Testcode:
import java.util.*;
public class Test {
public static void main(String args[]) {
long start = 0;
int size = 100000;
String[] strings = new String[size];
Random random = new Random();
for (int i = 0; i < size; i++)
strings[i] = "" + random.nextInt(size);
start = System.currentTimeMillis();
Arrays.sort(strings);
System.out.println(Arrays.binarySearch(strings, "" + (size - 1)));
System.out.println("Sort & Search : "
+ (System.currentTimeMillis() - start));
start = System.currentTimeMillis();
System.out.println(Arrays.binarySearch(strings, "" + (size - 1)));
System.out.println("Search : "
+ (System.currentTimeMillis() - start));
start = System.currentTimeMillis();
System.out.println(Arrays.asList(strings).contains("" + (size - 1)));
System.out.println("Contains : "
+ (System.currentTimeMillis() - start));
}
}
Ich verstehe diesen Code nicht. Sie sortieren das Array 'strings' und verwenden das gleiche (sortierte) Array in beiden Aufrufen von binarySearch. Wie kann das etwas anderes als eine HotSpot-Laufzeitoptimierung darstellen? Dasselbe gilt für den Aufruf von asList.contains. Sie erstellen eine Liste aus dem sortierten Array und führen dann contains mit dem höchsten Wert darauf aus. Das dauert natürlich seine Zeit. Was ist der Sinn dieses Tests? Ganz zu schweigen davon, dass es sich um einen unsachgemäß geschriebenen Microbenchmark handelt.
Da die binäre Suche nur auf eine sortierte Menge angewendet werden kann, ist Sortieren und Suchen die einzige Möglichkeit, die binäre Suche zu verwenden.
Die Sortierung kann aus einer Reihe anderer Gründe bereits erfolgt sein, z. B. könnte die Sortierung bei der Installation vorgenommen und nie geändert worden sein. Es ist sinnvoll, die Suchzeit an sich zu testen. Der Nachteil ist jedoch, dass es sich hierbei um ein weniger gutes Beispiel für Microbenchmarking handelt. Mikrobenchmarks sind in Java bekanntermaßen schwer zu bewerkstelligen und sollten beispielsweise die Ausführung des Testcodes in ausreichendem Maße beinhalten, um eine Hotspot-Optimierung zu erhalten, bevor der eigentliche Test ausgeführt wird, ganz zu schweigen davon, dass der eigentliche Testcode mehr als EINMAL mit einem Timer ausgeführt wird. Beispielhafte Fallstricke
Anstatt die schnelle Array-Initialisierungssyntax zu verwenden, könnten Sie sie auch gleich als Liste in ähnlicher Weise mit der Methode Arrays.asList initialisieren, z. B.:
public static final List<String> STRINGS = Arrays.asList("firstString", "secondString" ...., "lastString");
Dann können Sie (wie oben) vorgehen:
STRINGS.contains("the string you want to find");
Mit Java 8 können Sie einen Stream erstellen und prüfen, ob die Einträge im Stream "s"
:
String[] values = {"AB","BC","CD","AE"};
boolean sInArray = Arrays.stream(values).anyMatch("s"::equals);
Oder als generische Methode:
public static <T> boolean arrayContains(T[] array, T value) {
return Arrays.stream(array).anyMatch(value::equals);
}
Sie können die Arrays-Klasse um eine binäre Suche nach dem Wert durchzuführen. Wenn Ihr Array nicht sortiert ist, müssen Sie die Sortierfunktionen in derselben Klasse verwenden, um das Array zu sortieren und es dann zu durchsuchen.
Sie können die Sortierfunktionen in der gleichen Klasse verwenden, um das zu erreichen... Ich sollte das zu meiner Antwort hinzufügen.
Wird wahrscheinlich mehr kosten als die asList().contains() Ansatz, dann, ich denke. Es sei denn, Sie müssen diese Überprüfung sehr oft tun (aber wenn es nur eine statische Liste von Werten ist, die sortiert werden kann, um mit zu beginnen, um fair zu sein).
Wahr. Es gibt viele Variablen, um zu entscheiden, was am effektivsten wäre. Aber es ist gut, Optionen zu haben.
CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.
6 Stimmen
Das ist ein langer Weg, aber Sie können eine for-Schleife verwenden: "for (String s : VALUES) if (s.equals("MYVALUE")) return true;
1 Stimmen
Ja, es war mir fast peinlich, die Frage zu stellen, aber gleichzeitig war ich überrascht, dass sie noch nicht gestellt worden war. Es ist eine dieser APIs, mit denen ich einfach noch nicht in Berührung gekommen bin...
3 Stimmen
@camickr - ich habe eine fast identische Situation mit diesem hier: stackoverflow.com/a/223929/12943 Es wird immer wieder abgestimmt, obwohl es nur ein Copy/Paste aus der Sun-Dokumentation war. Ich schätze, die Bewertung basiert darauf, wie viel Hilfe man geleistet hat und nicht darauf, wie viel Mühe man sich gegeben hat - und vor allem darauf, wie schnell man es veröffentlicht hat! Vielleicht sind wir auf das Geheimnis von John Skeet gestoßen! Nun, gute Antwort, +1 für Sie.
3 Stimmen
Wenn Sie Apache Commons verwenden, dann org.apache.commons.lang.ArrayUtils.contains() tut dies für Sie.
0 Stimmen
@Zach: Sie tappen in die Falle des for-if-Antipatterns, tun Sie das nicht.
50 Stimmen
@camickr weil Leute, wie ich, eine Frage googeln, auf das SO-Ergebnis klicken, Ihre Antwort sehen, sie testen, es funktioniert, die Antwort hoch bewerten und dann gehen.
2 Stimmen
Ich vermisse wirklich eine einfache
indexOf
etcontains
injava.util.Arrays
- die beide unkomplizierte Schleifen enthalten würden. Ja, Sie können diese in 1 Minute schreiben; aber ich ging trotzdem zu StackOverflow in der Erwartung, sie irgendwo im JDK zu finden.