Wie zähle ich die Anzahl der vorkommen eines char in einen String?
Habe ich den string
a.b.c.d
Möchte ich zum zählen der vorkommen von '.' in einer umgangssprachlichen Weise, vorzugsweise ein one-liner.
(Vorher habe ich den Wunsch geäußert hatte, diese Einschränkung als "ohne loop", falls Sie sich Fragen, warum jeder versucht zu beantworten, ohne die Verwendung einer Schleife).
- warum die Schleife Abneigung?
- Hausaufgaben? Weil ich sonst nicht mehr sehen, die der Anforderung zu vermeiden, wird die Schleife.
- Nicht abgeneigt, eine Schleife, so viel wie der Suche nach einer idiomatischen one-liner.
- Loops gemacht wurden, für ein problem wie dieses, schreiben die Schleife in einem gemeinsamen Utility-Klasse, dann rufen Sie Ihren frisch gebackenen one-liner.
- Ähnliche Frage für Zeichenketten: stackoverflow.com/questions/767759/...
- Nur um zu zeigen-ich Schätze das finden des one-liners, Spaß und (wie ein echter Vorteil), die oft leicht zu merken, aber ich möchte darauf hinweisen, dass eine eigene Methode und ein loop ist besser in fast jeder Hinsicht--die Lesbarkeit und auch die Leistung. Die meisten, die "Elegante" Lösungen, die unten sind nicht sehr performant, da Sie mit der Reform strings/kopieren von Speicher, in der Erwägung, dass eine Schleife, die nur den eingescannten des string gezählt und vorkommen würde, einfach und schnell. Nicht, dass die Leistung soll in der Regel ein Faktor sein, aber schauen Sie nicht auf die eine Zeile über eine Schleife, und davon ausgehen, es wird besser.
- Mögliche Duplikate von vorkommen von Zeichen in einem Java-String
- In der Zukunft, wählen Sie bitte die höhere von Ihnen positiv bewertet werden die Fragen/Antworten als die doppelte Zielvorgabe.
Du musst angemeldet sein, um einen Kommentar abzugeben.
Mein 'idiomatischer one-liner" für diese ist:
Warum schreiben Sie es selbst, wenn es schon in commons-lang?
Spring-Frameworks oneliner für diese ist:
int count = CharMatcher.is('.').countIn("a.b.c.d");
...Als beantwortet von dogbane in eine doppelte Frage.Wie über dieses. Es nicht mit regexp unter so schneller als andere Lösungen und nicht eine Schleife verwenden.
StringUtils.countMatches
weil es zum reservieren von Speicher für die zurückgegebene Zeichenfolge. Noch eine schöne Lösung, wenn Leistung nicht wichtig ist.String.replace(String, String)
reguläre Ausdrücke verwenden? Nicht.
einen Platzhalter in einem regulären Ausdruck? Also, warum würden Sie nicht das ersetzen, erstellen Sie einen leeren string?int count = (sourceString.length() - sourceString.replace(searchString, "").length())/searcString.length();
String
ist nicht null-terminiert ist und nicht auf eine Schleife durch die Zeichen zu bestimmen, dessen Länge. Stattdessen verwendet es ein array von Zeichen intern.Array.length
ist O(1).Zusammenzufassen andere Antwort und was weiß ich, alle Möglichkeiten, dies zu tun mit einem one-liner:
1) Mit Apache Commons
2) Mit Spring-Frameworks
3) Mit ersetzen
4) Mit replaceAll (Fall 1)
5) Mit replaceAll (Fall 2)
6) Mit split
7) Mit Java8 (Fall 1)
8) Mit Java8 (Fall 2), kann für Sie besser sein unicode als Fall 1
9), Mit StringTokenizer
Kommentar: Seien Sie vorsichtig bei der StringTokenizer, für eine.b.c.d es wird funktionieren, aber für einen b....c....d oder ...ein.b.c.d oder a....b......c.....d... oder etc. es wird nicht funktionieren. Es wird einfach zählen . zwischen den Zeichen nur einmal
Mehr info in github
Perfomance test (mit JMH, mode = AverageTime, score
0.010
dann besser0.351
):"1?2?3 has 2".codePoints().filter((c) -> c == "?".codePointAt(0)).count()
Früher oder später etwas hat eine Schleife. Es ist weit einfacher für Sie zu schreiben, die (sehr einfache) Schleife zu nehmen, als so etwas wie
split
die ist viel leistungsfähiger, als Sie brauchen.Mit allen Mitteln zu Kapseln, die Schleife in eine eigene Methode, z.B.
Dann brauchen Sie nicht, die Schleife im Haupt - code- aber die Schleife muss irgendwo vorhanden sein.
length()
genannt wird, sehr oft, das könnte ein performance-Unterschied beim Umgang mit großen Streichern. Chris' Vorschlag, Reduzierung des Zugangs zulength()
zu einem einzigen Aufruf.length()
rufen Sie außerhalb der Schleife machen könnte Leistung schlimmer, wie erwähnt von @ShuggyCoUk ein paar Kommentare bis.for (int i = 0; (i = haystack.indexOf(needle, i)) >= 0; i++) { count++; }
kritisiert werden Kann, ein bisschen kryptisch, natürlich.needle
imhaystack
Analogie 😉length()
Anruf bei der Initialisierung der Bühne. Oben auf "weniger Funktionsaufrufe", es vermeidet auch das nicht-triviale Endlosschleifen.haystack
ist, würde ich diese version zu verwenden.Ich hatte eine Idee ähnlich wie Mladen, aber das Gegenteil...
replaceAll()
undlength()
. Gut, wenn es nicht sichtbar ist, existiert nicht ;o)ReplaceAll(".") ersetzen Sie alle Zeichen.
PhiLho ' s Lösung verwendet ReplaceAll("[^.]",""), die müssen nicht escaped werden, da [.] repräsentiert das Zeichen 'Punkt', nicht 'beliebige Zeichen'.
Mein 'idiomatischer one-liner' Lösung:
Habe keine Ahnung, warum eine Lösung, die verwendet StringUtils akzeptiert wird.
Einem kürzeren Beispiel ist
hier ist eine Lösung ohne Schleife:
gut, es ist eine Schleife, aber es ist unsichtbar 🙂
-- Yonatan
Ich weiß nicht, wie die Idee der Zuweisung in einen neuen string für diesen Zweck. Und da der string bereits ein char-array in den Rücken, wo es speichert es den Wert der Zeichenfolge.charAt() ist praktisch kostenlos.
funktioniert der trick, ohne zusätzliche Zuteilungen müssen Sammlung, in 1 Zeile oder weniger, nur mit J2SE.
charAt
durchläuft 16-bit-code der Punkte, die nicht Zeichen! Einchar
in Java ist nicht ein Zeichen. Also diese Antwort impliziert, dass es keine Unicode-Zeichen mit ein hohes Ersatzzeichen gleich den code Punkt desdelim
. Ich bin nicht sicher, ob es richtig ist, für den Punkt, aber im Allgemeinen ist es möglicherweise nicht korrekt.Okay, inspiriert von Yonatan Lösung, hier ist eine, die rein recursive - die einzige Bibliothek Methoden verwendet werden
length()
undcharAt()
, von denen keine Schleifen:Ob Rekursion zählt als Schleife hängt davon ab, welche genaue definition, die Sie verwenden, aber es ist wahrscheinlich so nah wie Sie erhalten.
Ich weiß nicht, ob die meisten JVMs, tun tail-Rekursion in diesen Tagen... wenn nicht, erhalten Sie den gleichnamigen stack-überlauf passend für lange strings, natürlich.
Inspiriert von Jon Skeet, ein nicht-loop-version, die nicht sprengen Sie Ihren stack. Auch nützlich Ausgangspunkt, wenn Sie möchten, verwenden Sie den fork-join-framework.
(Disclaimer: Nicht geprüft, nicht kompiliert, nicht sinnvoll.)
Vielleicht das beste (single-threaded, keine surrogate-pair-Unterstützung) Weise, es zu schreiben:
Nicht sicher über die Effizienz dieses, aber es ist der kürzeste code, den ich schreiben könnte, ohne das in 3rd-party-libs:
return (content.split(target, -1).length - 1);
. Standardmäßig Ereignisse am Ende der Zeichenfolge weggelassen, die in dem Array, die aus split(). Siehe die DokuMit java-8 Sie können auch mithilfe von streams zu erreichen. Offensichtlich gibt es eine iteration hinter den kulissen, aber Sie nicht schreiben Sie es explizit!
.codePoints()
statt.chars()
würde, dann unterstützen keine Unicode-Wert (einschließlich jene, die erfordern, ersatzpaare)Ebenfalls möglich reduzieren in Java 8 um dieses problem zu lösen:
Ausgabe:
Vollständiges Beispiel:
Nennen:
Der einfachste Weg, um die Antwort zu bekommen ist wie folgt:
Falls Sie mit Spring framework, könnten Sie auch "StringUtils" - Klasse.
Die Methode wäre "countOccurrencesOf".
Können Sie die
split()
- Funktion in nur einer Zeile codelimit
auf null gesetzt ist, in diesem überladenen split-Methode aufrufen. Ein Beispiel:"1##2#3#####".split("#")
liefert nur ein array der Größe 4 ([0:"1";1:""; 2:"2"; 3:"3"]
) statt Größe 9 ([0:"1"; 1:""; 2:"2"; 3:"3"; 4:""; 5:""; 6:""; 7:""; 8:""]
).Während Methoden verstecken können, es gibt keinen Weg, um zu zählen, ohne eine Schleife (oder Rekursion). Sie verwenden möchten, ein char[] aus Gründen der performance allerdings.
Mit replaceAll (RE) klingt nicht wie der beste Weg zu gehen.
Irgendwo im code etwas an die Schleife. Der einzige Weg, um dieses ist ein vollständiges abrollen der Schleife:
...etc, aber dann bist du diejenige, die Schleife, manuell im Quellcode-editor statt dem computer, die es ausgeführt wird. Siehe pseudocode:
Hier ist ein etwas anderer Stil Rekursion Lösung:
Warum nicht einfach aufgeteilt auf die Zeichen und dann die Länge des resultierenden Arrays. array-Länge wird immer die Anzahl der Instanzen + 1. Richtig?
Den folgenden source-code wird Ihnen nicht.von vorkommen einer bestimmten Zeichenkette in einem Wort, eingegeben durch user :-
Mit Eclipse-Sammlungen
Wenn du mehr als ein Zeichen zu zählen, die Sie verwenden können, eine
CharBag
wie folgt:Hinweis: ich bin ein committer für Eclipse Sammlungen.
Gut, mit einer ganz ähnlichen Aufgabe, ich stolperte über dieses Thread.
Ich sehe keine Programmiersprache Einschränkung und da groovy läuft auf einer java-vm:
Hier ist, wie ich in der Lage war, mein Problem zu lösen Verwendung von Groovy.
getan.
Versuchen Sie diese Methode:
Warum sind Sie versuchen zu vermeiden, die Schleife? Ich meine, Sie können nicht zählen, die "Anzahl" Punkte, ohne zu überprüfen, jedes einzelne Zeichen des Strings, und rufen Sie eine beliebige Funktion, irgendwie wird es Schleife. Dies ist String.ersetzen, sollte eine Schleife überprüfen, ob der string angezeigt wird, so kann es ersetzen Sie jedes einzelne vorkommen.
Wenn Sie versuchen, den Ressourceneinsatz reduzieren, werden Sie es nicht tun würde, weil Sie erstellen Sie eine neue Zeichenfolge nur zum zählen der Punkte.
Nun, wenn wir reden über die rekursive "enter code here" - Methode, jemand sagte, dass es scheitern wird, aufgrund einer OutOfMemmoryException, ich glaube, er vergaß StackOverflowException.
Also meine Methode würde wie folgt Aussehen (ich weiß, es ist wie die anderen, aber dieses problem erfordert die Schleife):
Sehe ich eine Menge tricks und so verwendet wird. Nun, ich bin nicht gegen schöne tricks, aber ich persönlich mag einfach die Methoden aufrufen, die sind gemeint um die Arbeit zu tun, so habe ich doch eine andere Antwort.
Beachten Sie, dass wenn die Leistung jedes Problem Jon Skeet Antwort statt. Dieses ist ein wenig mehr verallgemeinert und damit ein wenig mehr lesbar, meiner Meinung nach (und, natürlich, wiederverwendbar für Zeichenfolgen und mustern).
Gut, es ist ein Fall von zu wissen, Ihre Java -, vor allem Ihre grundlegende grundlegende Verständnis der Sammlung von Klassen, die bereits in Java. Wenn man sich während des gesamten posting hier, es ist so ziemlich alles kurz von Stephen Hawkings Erklärung, den Ursprung des Universums, Darwin 's Taschenbuch auf Evolution und Gene Roddenberry' s Star Trek-cast-Auswahl, warum Sie ging mit William Shatner kurz, wie Sie dies schnell und einfach tun...
... muss ich mehr sagen?
parts
array, welches noch reserviert werden und später von der garbage Collection eingesammelt. Völlig unnötiger overhead. Versuchen Sie, dies zu tun in einer engen Schleife.Was ist unter rekursiver algo.Das ist auch die lineare Zeit.
Versuchen, diesen code:
Wenn Sie zählen möchten, die keine. von gleichen Zeichen in einem string 'SELEN' oder Sie drucken möchten, die eindeutige Zeichen von der Zeichenkette 'SELEN'.
/******************** AUSGABE **********************/
SELEN
SELNIUM
S : 1,E : 2,L : 1,E : 1,N : 1,I : 1,U : 1
char
ist ein UTF-16-code-unit. Der Wertebereich ist 0..Charakter.MAX_VALUE. Ihr Algorithmus funktioniert, wenn das Ziel ist, die Anzahl vorkommen von UTF-16 code-Einheiten.Ich habe versucht, auf Ihre Frage mit einer switch-Anweisung, aber ich Bedarf noch eine for-Schleife Parsen der Zeichenfolge . fühlen Sie sich frei zu kommentieren, wenn ich kann, verbessern den code
}