ฉันจะใช้ลูป for-each loop กับตัวละครทุกตัวใน String ได้อย่างไร


189

ดังนั้นฉันต้องการย้ำสำหรับตัวละครแต่ละตัวในสตริง

ดังนั้นฉันคิดว่า:

for (char c : "xyz")

แต่ฉันได้รับข้อผิดพลาดของคอมไพเลอร์:

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

ฉันจะทำสิ่งนี้ได้อย่างไร

คำตอบ:


333

วิธีที่ง่ายที่สุดสำหรับการใช้ทุกคนcharในStringคือtoCharArray():

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

สิ่งนี้ช่วยให้คุณกระชับสำหรับแต่ละโครงสร้าง แต่น่าเสียดายString(ซึ่งไม่เปลี่ยนรูป) ต้องดำเนินการคัดลอกการป้องกันเพื่อสร้างchar[] (ซึ่งไม่แน่นอน) ดังนั้นจึงมีค่าปรับบางอย่าง

จากเอกสาร :

[ toCharArray()คืนค่า] อาร์เรย์อักขระที่จัดสรรใหม่ซึ่งความยาวคือความยาวของสตริงนี้และมีเนื้อหาที่ถูกเตรียมใช้งานเพื่อให้มีลำดับอักขระที่แสดงโดยสตริงนี้

มีวิธีการวนซ้ำอย่างละเอียดมากกว่าตัวอักษรในอาร์เรย์ (ปกติสำหรับลูปCharacterIterator, ฯลฯ ) แต่ถ้าคุณยินดีจ่ายค่าใช้จ่ายtoCharArray()สำหรับแต่ละคนนั้นจะรัดกุมที่สุด


1
คอมไพเลอร์จะรับรู้หรือไม่ว่าการทำสำเนาจริงนั้นไม่จำเป็นและใช้การปรับแต่งที่เหมาะสม
Pacerier

1
@Pacerier ไม่คอมไพเลอร์ Java ปัจจุบันจะไม่ปรับโค้ดให้เหมาะสม
RAnders00

1
@ RAnders00 ดังนั้นในกรณีtoCharArray( )นี้เรียกว่า 3 ครั้ง?
denvercoder9

1
ด้วยความยาวสตริงของ211900000เวลาที่ใช้ในการทำให้สมบูรณ์for (char c : str.toCharArray()) { }คือ ~ 250ms และเวลาที่ใช้ในการทำให้เสร็จสมบูรณ์for (char c : charArray) { }คือ <10ms แน่นอนว่าค่าเวลาเหล่านี้จะขึ้นอยู่กับฮาร์ดแวร์ แต่สิ่งที่ซื้อกลับบ้านก็คือวิธีหนึ่งมีค่าใช้จ่ายสูงกว่าวิธีอื่นอย่างมีนัยสำคัญ
denvercoder9

7
@RafiduzzamanSonnet: ไม่, toCharArray()ไม่ได้อยู่ใน body loop; มันถูกเรียกเพียงครั้งเดียวแล้วลูปจะวนซ้ำแถวนั้น (สำหรับแต่ละลูปนั้นแตกต่างจากลูปทั่วไปforซึ่งประเมินการหยุดเงื่อนไขในแต่ละการวนซ้ำ)
ไม่ใช่แค่ just-yeti

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

 


7
OP คาดหวังการหายใจเข้าวนรอบ
AmitG

3
ลงคะแนนเนื่องจากนี่ไม่ใช่สิ่งที่ OP ต้องการโดยเฉพาะ แม้ว่านี่จะเป็นโซลูชันที่ถูกต้อง แต่ก็ไม่ใช่สิ่งที่ถูกถาม
ไซเรน

1
ไม่ว่าจะคาดหวังอะไร OP นี้มีประสิทธิภาพที่ดีกว่าสำหรับแต่ละฉันเดา
Eric Wang

9

อีกโซลูชันที่มีประโยชน์คุณสามารถทำงานกับสตริงนี้เป็นอาร์เรย์ของสตริงได้

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

สง่างาม แต่น่าเสียดายที่มันไม่ทำงานหากองค์ประกอบใด ๆ ของสตริงเป็นsplit()แม็พกับอักขระ Java มากกว่าหนึ่งตัวซึ่งเป็นกรณีของอีโมติคอนเกือบทั้งหมด ตัวอย่างเช่นรูปแบบของตัวอย่างนี้จะวนซ้ำสี่ครั้งแทนที่จะเป็นสามครั้ง:for (String s : "x😁z".split("")) { System.out.println(s); }
skomisa

5

คุณต้องแปลงวัตถุ String เป็นอาร์เรย์ของ char โดยใช้วิธีtoCharArray() ของคลาส 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

ในJava 8เราสามารถแก้ปัญหาได้ดังนี้:

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

chars ของเมธอด () จะคืนค่าIntStreamตามที่กล่าวไว้ในdoc :

ส่งคืนสตรีมของ int ที่ไม่มีการขยายค่าถ่านจากลำดับนี้ อักขระใด ๆ ที่แม็พกับจุดโค้ดตัวแทนจะถูกส่งผ่านโดยไม่ถูกตีความ หากมีการเปลี่ยนแปลงลำดับในขณะที่กระแสกำลังอ่านผลลัพธ์จะไม่ได้กำหนด

ทำไมต้องใช้forEachOrderedและไม่ได้forEach?

พฤติกรรมของforEachคือ nondeterministic อย่างชัดเจนโดยที่การforEachOrderedดำเนินการสำหรับแต่ละองค์ประกอบของสตรีมนี้ในลำดับการเผชิญหน้าของสตรีมหากสตรีมมีลำดับการเผชิญหน้าที่กำหนดไว้ ดังนั้นforEachไม่รับประกันว่าคำสั่งจะถูกเก็บไว้ ตรวจสอบคำถามนี้เพิ่มเติม

เราสามารถใช้codePoints()พิมพ์ดูคำตอบนี้สำหรับรายละเอียดเพิ่มเติม


สิ่งนี้จะสร้างวัตถุหลายรายการดังนั้นคำตอบนี้จะไม่สมบูรณ์หากไม่มีข้อแม้ที่อาจมีประสิทธิภาพน้อยกว่าการวนรอบแบบง่าย
toolforger

4

แต่น่าเสียดายที่ Java ไม่ได้ทำให้การดำเนินการString Iterable<Character>สามารถทำได้อย่างง่ายดาย มีStringCharacterIteratorแต่ที่ไม่ได้ใช้Iterator... ดังนั้นทำด้วยตัวเอง:

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++);
            }
        };
    }
}

ตอนนี้คุณสามารถ (ค่อนข้าง) วิ่งได้อย่างง่ายดายfor (char c : new CharSequenceCharacterIterable("xyz"))...


3

ถ้าคุณใช้ Java 8 คุณสามารถใช้chars()ในStringที่จะได้รับStreamของตัวละคร แต่คุณจะต้องโยนintกลับไปcharเป็นส่งกลับchars()IntStream

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

ถ้าคุณใช้ Java 8 กับคราสคอลเลกชัน , คุณสามารถใช้CharAdapterระดับวิธีการที่มีแลมบ์ดาหรือวิธีการอ้างอิงถึงย้ำกว่าทุกตัวอักษรในส่วนforEachString

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

ตัวอย่างเฉพาะนี้ยังสามารถใช้การอ้างอิงวิธีการ

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

หมายเหตุ: ฉันเป็นคอมมิชชันสำหรับ Eclipse Collections


1

คุณสามารถใช้แลมบ์ดาได้ในกรณีนี้

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

-7

สำหรับ Travers String คุณยังสามารถใช้charAt()กับสตริงได้

ชอบ :

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() เป็นวิธีการจัดการสตริงใน java ซึ่งช่วยในการ Travers สตริงสำหรับตัวละครที่เฉพาะเจาะจง


2
คุณรู้อะไรfor (char st: "xyz".toCharArray()) {}ไหม
AmitG

สิ่งนี้จะไม่คอมไพล์
Maroun

-1 นอกหัวข้อ (หัวข้อ: สำหรับแต่ละคน) และใช้ charAt แทน charAT
peenut
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.