Jak zastosować pętlę dla każdego znaku do każdego znaku w ciągu?


189

Więc chcę iterować dla każdego znaku w ciągu.

Więc pomyślałem:

for (char c : "xyz")

ale pojawia się błąd kompilatora:

MyClass.java:20: foreach not applicable to expression type

W jaki sposób mogę to zrobić?

Odpowiedzi:


333

Najprostszym sposobem dla każdego, każdy charw sposób Stringjest użycie toCharArray():

for (char ch: "xyz".toCharArray()) {
}

Daje to zwięzłość konstrukcji dla każdego, ale niestety String(która jest niezmienna) musi wykonać kopię obronną, aby wygenerować char[](którą można modyfikować), więc istnieje pewna kara kosztowa.

Z dokumentacji :

[ toCharArray()zwraca] nowo przydzieloną tablicę znaków, której długość jest długością tego łańcucha i której treść jest inicjalizowana, aby zawierała sekwencję znaków reprezentowaną przez ten ciąg.

Istnieje więcej pełnych sposobów iteracji znaków w tablicy (zwykłe dla pętli CharacterIteratoritp.), Ale jeśli chcesz zapłacić toCharArray()za to, każdy z nich jest najbardziej zwięzły.


1
Czy kompilator rozpozna, że ​​prawdziwa kopia nie jest potrzebna i zastosuje odpowiednie optymalizacje?
Pacerier

1
@Pacerier Nie, obecne kompilatory Java nigdy nie zoptymalizują kodu.
RAnders00

1
@ RAnders00 Więc w tym przypadku toCharArray( )nazywa się 3 razy?
denvercoder9,

1
Przy długości ciągu wynoszącej 211900000czas ukończenia for (char c : str.toCharArray()) { }wynosi ~ 250 ms, a czas ukończenia for (char c : charArray) { }wynosi <10 ms. Oczywiście te wartości czasu będą zależeć od sprzętu, ale na wynos jest to, że jedna metoda jest znacznie kosztowna niż druga.
denvercoder9,

7
@RafiduzzamanSonnet: Nie, toCharArray()nie ma go w ciele pętli; jest wywoływany tylko raz, a następnie pętla przechodzi przez wynikową tablicę. (Pętla dla każdego jest inna niż ogólna pętla for, która ocenia warunek zatrzymania każdej iteracji.)
not-just-yeti

50
String s = "xyz";
for(int i = 0; i < s.length(); i++)
{
   char c = s.charAt(i);
}

 


7
OP oczekuje osłabienia dla pętli.
AmitG

3
Głosowanie w dół, ponieważ nie jest to dokładnie to, o co poprosił OP. Chociaż jest to prawidłowe rozwiązanie, nie jest to o co pytano
syreny

1
Bez względu na to, czego oczekiwał PO, ma lepszą wydajność niż w przypadku każdego.
Eric Wang,

9

Innym przydatnym rozwiązaniem, możesz pracować z tym ciągiem jako tablicą Ciągu

for (String s : "xyz".split("")) {
    System.out.println(s);
}

Elegancki, ale niestety nie działa, jeśli jakikolwiek element ciągu jest split()odwzorowany na więcej niż jedną postać Java, co ma miejsce w przypadku prawie wszystkich emotikonów. Na przykład ta odmiana twojego przykładu for (String s : "x😁z".split("")) { System.out.println(s); }
zapętli się

5

Musisz przekonwertować obiekt String na tablicę znaków przy użyciu metody toCharArray() klasy String:

String str = "xyz";
char arr[] = str.toCharArray(); // convert the String object to array of char

// iterate over the array using the for-each loop.       
for(char c: arr){
    System.out.println(c);
}

4

W Javie 8 możemy to rozwiązać jako:

String str = "xyz";
str.chars().forEachOrdered(i -> System.out.print((char)i));    

Metoda chars () zwraca IntStreamjak wspomniano w doc :

Zwraca strumień int rozszerzających zera wartości char z tej sekwencji. Każdy znak odwzorowany na zastępczy punkt kodowy jest przekazywany przez nieinterpretowany. Jeśli sekwencja zostanie zmutowana podczas odczytywania strumienia, wynik jest niezdefiniowany.

Dlaczego stosowanie forEachOrderednie iforEach ?

Zachowanie forEachjest wyraźnie niedeterministyczne, gdy jako forEachOrderedwykonuje akcję dla każdego elementu tego strumienia, w kolejności spotkań strumienia, jeśli strumień ma zdefiniowaną kolejność spotkań. Tak forEachnie gwarantuje, że zamówienie zostanie utrzymane. Sprawdź także to pytanie aby uzyskać więcej.

Możemy również użyć codePoints()do drukowania, zobacz tę odpowiedź, aby uzyskać więcej informacji.


Tworzy to wiele obiektów, więc odpowiedź nie jest kompletna bez zastrzeżenia, że ​​może to być mniej wydajne niż zwykła pętla indeksowana.
toolforger

4

Niestety Java nie tworzy Stringimplementacji Iterable<Character>. Można to łatwo zrobić. Jest, StringCharacterIteratorale to nawet nie implementuje Iterator... Więc stwórz własne:

public class CharSequenceCharacterIterable implements Iterable<Character> {
    private CharSequence cs;

    public CharSequenceCharacterIterable(CharSequence cs) {
        this.cs = cs;
    }

    @Override
    public Iterator<Character> iterator() {
        return new Iterator<Character>() {
            private int index = 0;

            @Override
            public boolean hasNext() {
                return index < cs.length();
            }

            @Override
            public Character next() {
                return cs.charAt(index++);
            }
        };
    }
}

Teraz możesz (nieco) łatwo uruchomić for (char c : new CharSequenceCharacterIterable("xyz"))...


3

Jeśli używasz języka Java 8, możesz użyć znaku chars()a, Stringaby uzyskać jeden Streamze znaków, ale musisz przerzucić go z intpowrotem na a, charponieważ chars()zwraca an IntStream.

"xyz".chars().forEach(i -> System.out.print((char)i));

Jeśli używasz Java 8 z Eclipse Collections , możesz użyćCharAdapterforEach metody class z lambda lub odwołania do metody, aby iterować wszystkie znaki w String.

Strings.asChars("xyz").forEach(c -> System.out.print(c));

W tym konkretnym przykładzie można również użyć odwołania do metody.

Strings.asChars("xyz").forEach(System.out::print)

Uwaga: jestem osobą odpowiedzialną za kolekcje Eclipse.


1

W tym przypadku możesz również użyć lambda.

    String s = "xyz";
    IntStream.range(0, s.length()).forEach(i -> {
        char c = s.charAt(i);
    });

-7

Do Travers a String możesz także użyć charAt() z tym łańcuchem.

lubić :

String str = "xyz"; // given String
char st = str.charAt(0); // for example we take 0 index element 
System.out.println(st); // print the char at 0 index 

charAt() to metoda obsługi napisów w Javie, która pomaga przemierzać ciąg znaków dla określonego znaku.


2
wiesz co for (char st: "xyz".toCharArray()) {}to jest
AmitG

To się nie skompiluje.
Maroun

-1 poza tematem (temat: dla każdego) i użyj charAt zamiast charAT
peenut
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.