Mam sznurek
a.b.c.d
Chcę policzyć wystąpienia „.” w sposób idiomatyczny, najlepiej jednowarstwowy.
(Wcześniej wyrażałem to ograniczenie jako „bez pętli”, na wypadek, gdy zastanawiasz się, dlaczego wszyscy próbują odpowiedzieć bez użycia pętli).
Mam sznurek
a.b.c.d
Chcę policzyć wystąpienia „.” w sposób idiomatyczny, najlepiej jednowarstwowy.
(Wcześniej wyrażałem to ograniczenie jako „bez pętli”, na wypadek, gdy zastanawiasz się, dlaczego wszyscy próbują odpowiedzieć bez użycia pętli).
Odpowiedzi:
Mój „idiomatyczny jedno-liniowiec” do tego to:
int count = StringUtils.countMatches("a.b.c.d", ".");
Po co pisać, gdy jest już w języku wspólnym ?
Oneliner firmy Spring Framework to:
int occurance = StringUtils.countOccurrencesOf("a.b.c.d", ".");
int count = CharMatcher.is('.').countIn("a.b.c.d");
... Jak odpowiedział dogbane w duplikacie pytania.
Co powiesz na to. Nie używa wyrażeń regularnych pod spodem, więc powinno być szybsze niż niektóre inne rozwiązania i nie będzie używać pętli.
int count = line.length() - line.replace(".", "").length();
Podsumuj inną odpowiedź i to, co wiem na wszystkie sposoby, aby to zrobić za pomocą jednej linijki:
String testString = "a.b.c.d";
1) Korzystanie z Apache Commons
int apache = StringUtils.countMatches(testString, ".");
System.out.println("apache = " + apache);
2) Korzystanie z Spring Framework
int spring = org.springframework.util.StringUtils.countOccurrencesOf(testString, ".");
System.out.println("spring = " + spring);
3) Za pomocą zamiany
int replace = testString.length() - testString.replace(".", "").length();
System.out.println("replace = " + replace);
4) Korzystanie z replaceAll (przypadek 1)
int replaceAll = testString.replaceAll("[^.]", "").length();
System.out.println("replaceAll = " + replaceAll);
5) Korzystanie z replaceAll (przypadek 2)
int replaceAllCase2 = testString.length() - testString.replaceAll("\\.", "").length();
System.out.println("replaceAll (second case) = " + replaceAllCase2);
6) Korzystanie z podziału
int split = testString.split("\\.",-1).length-1;
System.out.println("split = " + split);
7) Korzystanie z Java8 (przypadek 1)
long java8 = testString.chars().filter(ch -> ch =='.').count();
System.out.println("java8 = " + java8);
8) Korzystanie z Java8 (przypadek 2) może być lepsze dla Unicode niż przypadek 1
long java8Case2 = testString.codePoints().filter(ch -> ch =='.').count();
System.out.println("java8 (second case) = " + java8Case2);
9) Korzystanie z StringTokenizer
int stringTokenizer = new StringTokenizer(" " +testString + " ", ".").countTokens()-1;
System.out.println("stringTokenizer = " + stringTokenizer);
Z komentarza : Uważaj na StringTokenizer, dla abcd zadziała, ale dla ... bc ... d lub ... abcd lub a ... b ...... c ..... d ... lub itp. to nie zadziała. To się po prostu liczy. między postaciami tylko raz
Więcej informacji w github
Test wydajności (przy użyciu JMH , mode = AverageTime, 0.010
lepiej niż wynik 0.351
):
Benchmark Mode Cnt Score Error Units
1. countMatches avgt 5 0.010 ± 0.001 us/op
2. countOccurrencesOf avgt 5 0.010 ± 0.001 us/op
3. stringTokenizer avgt 5 0.028 ± 0.002 us/op
4. java8_1 avgt 5 0.077 ± 0.005 us/op
5. java8_2 avgt 5 0.078 ± 0.003 us/op
6. split avgt 5 0.137 ± 0.009 us/op
7. replaceAll_2 avgt 5 0.302 ± 0.047 us/op
8. replace avgt 5 0.303 ± 0.034 us/op
9. replaceAll_1 avgt 5 0.351 ± 0.045 us/op
"1🚲2🚲3 has 2".codePoints().filter((c) -> c == "🚲".codePointAt(0)).count()
Wcześniej czy później coś musi się zapętlić. O wiele łatwiej jest napisać (bardzo prostą) pętlę niż użyć czegoś, split
co jest o wiele potężniejsze niż potrzebujesz.
Za wszelką cenę obuduj pętlę osobną metodą, np
public static int countOccurrences(String haystack, char needle)
{
int count = 0;
for (int i=0; i < haystack.length(); i++)
{
if (haystack.charAt(i) == needle)
{
count++;
}
}
return count;
}
Wtedy nie potrzebujesz pętli w głównym kodzie - ale pętla musi gdzieś tam być.
length()
wywołania poza pętlę może pogorszyć wydajność , o czym wspomniał @ShuggyCoUk w kilku komentarzach.
Miałem pomysł podobny do Mladena, ale odwrotnie ...
String s = "a.b.c.d";
int charCount = s.replaceAll("[^.]", "").length();
println(charCount);
replaceAll()
i length()
. Cóż, jeśli nie jest widoczny, to nie istnieje; o)
String s = "a.b.c.d";
int charCount = s.length() - s.replaceAll("\\.", "").length();
ReplaceAll („.”) Zastąpi wszystkie znaki.
Rozwiązanie PhiLho wykorzystuje ReplaceAll („[^.]”, „”), Którego nie trzeba usuwać, ponieważ [.] Reprezentuje znak „kropka”, a nie „dowolny znak”.
Moje rozwiązanie „idiomatic one-liner”:
int count = "a.b.c.d".length() - "a.b.c.d".replace(".", "").length();
Nie mam pojęcia, dlaczego akceptowane jest rozwiązanie korzystające z StringUtils.
Krótszy przykład to
String text = "a.b.c.d";
int count = text.split("\\.",-1).length-1;
oto rozwiązanie bez pętli:
public static int countOccurrences(String haystack, char needle, int i){
return ((i=haystack.indexOf(needle, i)) == -1)?0:1+countOccurrences(haystack, needle, i+1);}
System.out.println("num of dots is "+countOccurrences("a.b.c.d",'.',0));
Cóż, jest pętla, ale jest niewidoczna :-)
- Yonatan
Nie podoba mi się pomysł przydzielenia nowego ciągu do tego celu. A ponieważ ciąg znaków ma już tablicę char z tyłu, w której przechowuje swoją wartość, String.charAt () jest praktycznie wolny.
for(int i=0;i<s.length();num+=(s.charAt(i++)==delim?1:0))
robi lewę, bez dodatkowych przydziałów, które wymagają zbierania, w 1 linii lub mniej, tylko z J2SE.
charAt
iteruje 16-bitowe punkty kodu, a nie znaki! A char
w Javie nie jest znakiem. Tak więc ta odpowiedź sugeruje, że nie może być żadnego symbolu Unicode z wysoką wartością zastępczą równą punktowi kodowemu delim
. Nie jestem pewien, czy jest poprawny dla kropki, ale ogólnie może być nieprawidłowy.
Ok, zainspirowany rozwiązaniem Yonatan, oto metoda czysto rekurencyjna - jedynymi używanymi metodami bibliotecznymi są length()
i charAt()
żadna z nich nie zapętla:
public static int countOccurrences(String haystack, char needle)
{
return countOccurrences(haystack, needle, 0);
}
private static int countOccurrences(String haystack, char needle, int index)
{
if (index >= haystack.length())
{
return 0;
}
int contribution = haystack.charAt(index) == needle ? 1 : 0;
return contribution + countOccurrences(haystack, needle, index+1);
}
To, czy rekurencja liczy się jako zapętlenie, zależy od dokładnej definicji, której używasz, ale prawdopodobnie jest ona tak bliska, jak to tylko możliwe.
Nie wiem, czy obecnie większość maszyn JVM wykonuje rekursję ogona ... jeśli nie, oczywiście otrzymasz przepełnienie stosu dla odpowiednio długich łańcuchów.
Zainspirowany przez Jona Skeeta, wersję bez pętli, która nie wysadzi twojego stacka. Przydatny również punkt początkowy, jeśli chcesz korzystać ze szkieletu łączenia widelca.
public static int countOccurrences(CharSequeunce haystack, char needle) {
return countOccurrences(haystack, needle, 0, haystack.length);
}
// Alternatively String.substring/subsequence use to be relatively efficient
// on most Java library implementations, but isn't any more [2013].
private static int countOccurrences(
CharSequence haystack, char needle, int start, int end
) {
if (start == end) {
return 0;
} else if (start+1 == end) {
return haystack.charAt(start) == needle ? 1 : 0;
} else {
int mid = (end+start)>>>1; // Watch for integer overflow...
return
countOccurrences(haystack, needle, start, mid) +
countOccurrences(haystack, needle, mid, end);
}
}
(Zastrzeżenie: Nie przetestowano, nie skompilowano, nie ma sensu.)
Być może najlepszy sposób na napisanie tego (jednowątkowy, bez pary zastępczej):
public static int countOccurrences(String haystack, char needle) {
int count = 0;
for (char c : haystack.toCharArray()) {
if (c == needle) {
++count;
}
}
return count;
}
Nie jestem pewien co do wydajności tego, ale jest to najkrótszy kod, jaki mógłbym napisać bez korzystania z bibliotek stron trzecich:
public static int numberOf(String target, String content)
{
return (content.split(target).length - 1);
}
Z java-8możesz również użyć strumieni, aby to osiągnąć. Oczywiście za kulisami jest iteracja, ale nie musisz pisać tego wprost!
public static long countOccurences(String s, char c){
return s.chars().filter(ch -> ch == c).count();
}
countOccurences("a.b.c.d", '.'); //3
countOccurences("hello world", 'l'); //3
.codePoints()
zamiast .chars()
tego obsługiwałoby wtedy dowolną wartość Unicode (włączając te wymagające par zastępczych)
Możliwe jest również użycie funkcji zmniejszania w Javie 8, aby rozwiązać ten problem:
int res = "abdsd3$asda$asasdd$sadas".chars().reduce(0, (a, c) -> a + (c == '$' ? 1 : 0));
System.out.println(res);
Wynik:
3
Pełna próbka:
public class CharacterCounter
{
public static int countOccurrences(String find, String string)
{
int count = 0;
int indexOf = 0;
while (indexOf > -1)
{
indexOf = string.indexOf(find, indexOf + 1);
if (indexOf > -1)
count++;
}
return count;
}
}
Połączenie:
int occurrences = CharacterCounter.countOccurrences("l", "Hello World.");
System.out.println(occurrences); // 3
Najprostszym sposobem na uzyskanie odpowiedzi jest:
public static void main(String[] args) {
String string = "a.b.c.d";
String []splitArray = string.split("\\.",-1);
System.out.println("No of . chars is : " + (splitArray.length-1));
}
Jeśli używasz frameworka Spring, możesz również użyć klasy „StringUtils”. Metodą będzie „countOccurrencesOf”.
Możesz użyć tej split()
funkcji w jednym kodzie linii
int noOccurence=string.split("#",-1).length-1;
limit
jest ustawiony na zero w tym przeciążonym wywołaniu metody split. Przykład: "1##2#3#####".split("#")
zwróci tylko tablicę o rozmiarze 4 ( [0:"1";1:""; 2:"2"; 3:"3"]
) zamiast wielkości 9 ( [0:"1"; 1:""; 2:"2"; 3:"3"; 4:""; 5:""; 6:""; 7:""; 8:""]
).
public static int countOccurrences(String container, String content){
int lastIndex, currIndex = 0, occurrences = 0;
while(true) {
lastIndex = container.indexOf(content, currIndex);
if(lastIndex == -1) {
break;
}
currIndex = lastIndex + content.length();
occurrences++;
}
return occurrences;
}
import java.util.Scanner;
class apples {
public static void main(String args[]) {
Scanner bucky = new Scanner(System.in);
String hello = bucky.nextLine();
int charCount = hello.length() - hello.replaceAll("e", "").length();
System.out.println(charCount);
}
}// COUNTS NUMBER OF "e" CHAR´s within any string input
Chociaż metody mogą to ukryć, nie ma możliwości liczenia bez pętli (lub rekurencji). Chcesz jednak użyć char [] ze względu na wydajność.
public static int count( final String s, final char c ) {
final char[] chars = s.toCharArray();
int count = 0;
for(int i=0; i<chars.length; i++) {
if (chars[i] == c) {
count++;
}
}
return count;
}
Korzystanie z replaceAll (czyli RE) nie brzmi jak najlepsza droga.
Z całkiem podobnym zadaniem natknąłem się na ten wątek. Nie widziałem żadnych ograniczeń języka programowania, a ponieważ groovy działa na Javie vm: Oto, jak mogłem rozwiązać mój problem za pomocą Groovy.
"a.b.c.".count(".")
gotowy.
Znacznie łatwiejszym rozwiązaniem byłoby podzielenie łańcucha na podstawie znaku, z którym go dopasujesz.
Na przykład,
int getOccurences(String characters, String string) {
String[] words = string.split(characters);
return words.length - 1;
}
Zwróci 4 w przypadku:
getOccurences("o", "something about a quick brown fox");
Gdzieś w kodzie coś musi zapętlić. Jedynym sposobem na obejście tego jest całkowite rozwinięcie pętli:
int numDots = 0;
if (s.charAt(0) == '.') {
numDots++;
}
if (s.charAt(1) == '.') {
numDots++;
}
if (s.charAt(2) == '.') {
numDots++;
}
... itd., ale to Ty robisz pętlę ręcznie w edytorze źródłowym - zamiast komputera, który go uruchomi. Zobacz pseudokod:
create a project
position = 0
while (not end of string) {
write check for character at position "position" (see above)
}
write code to output variable "numDots"
compile program
hand in homework
do not think of the loop that your "if"s may have been optimized and compiled to
Oto nieco inne rozwiązanie rekurencyjne w stylu:
public static int countOccurrences(String haystack, char needle)
{
return countOccurrences(haystack, needle, 0);
}
private static int countOccurrences(String haystack, char needle, int accumulator)
{
if (haystack.length() == 0) return accumulator;
return countOccurrences(haystack.substring(1), needle, haystack.charAt(0) == needle ? accumulator + 1 : accumulator);
}
Dlaczego nie po prostu podzielić na postać, a następnie uzyskać długość wynikowej tablicy. długość tablicy zawsze będzie liczbą wystąpień + 1. Prawda?
Poniższy kod źródłowy poda liczbę wystąpień danego ciągu w słowie wprowadzonym przez użytkownika: -
import java.util.Scanner;
public class CountingOccurences {
public static void main(String[] args) {
Scanner inp= new Scanner(System.in);
String str;
char ch;
int count=0;
System.out.println("Enter the string:");
str=inp.nextLine();
while(str.length()>0)
{
ch=str.charAt(0);
int i=0;
while(str.charAt(i)==ch)
{
count =count+i;
i++;
}
str.substring(count);
System.out.println(ch);
System.out.println(count);
}
}
}