วิธีที่ง่ายที่สุด / ดีที่สุด / ถูกต้องที่สุดในการวนซ้ำผ่านอักขระของสตริงใน Java คืออะไร


341

StringTokenizer? แปลงStringไปเป็น a char[]และทำซ้ำมากกว่านั้นหรือไม่ อื่น ๆ อีก?



3
ดูเพิ่มเติมที่stackoverflow.com/questions/1527856/…
rogerdpack

1
ดูเพิ่มเติมที่stackoverflow.com/questions/8894258/…มาตรฐานแสดง String.charAt () เร็วที่สุดสำหรับสตริงขนาดเล็กและการใช้การสะท้อนเพื่ออ่านอาร์เรย์ char โดยตรงนั้นเร็วที่สุดสำหรับสตริงขนาดใหญ่
Jonathan


คำตอบ:


363

ฉันใช้สำหรับวนรอบเพื่อย้ำสตริงและใช้charAt()เพื่อให้ตัวละครแต่ละตัวตรวจสอบมัน เนื่องจาก String ถูกนำมาใช้กับอาร์เรย์charAt()วิธีการคือการดำเนินการเวลาคงที่

String s = "...stuff...";

for (int i = 0; i < s.length(); i++){
    char c = s.charAt(i);        
    //Process char
}

นั่นคือสิ่งที่ฉันจะทำ ดูเหมือนง่ายที่สุดสำหรับฉัน

เท่าที่ถูกต้องไปฉันไม่เชื่อว่ามีอยู่ที่นี่ มันขึ้นอยู่กับสไตล์ส่วนตัวของคุณ


3
คอมไพเลอร์อินไลน์ method length () หรือไม่
Uri

7
มันอาจจะมีความยาวแบบอินไลน์ () นั่นคือวิธีการยกที่อยู่เบื้องหลังเรียกบางเฟรม แต่มันมีประสิทธิภาพมากขึ้นในการทำเช่นนี้สำหรับ (int i = 0, n = s.length (); i <n; i ++) {ถ่าน c = s.charAt (i); }
Dave Cheney

32
เกะกะรหัสของคุณสำหรับการขนาดเล็กได้รับประสิทธิภาพ โปรดหลีกเลี่ยงสิ่งนี้จนกว่าคุณจะตัดสินใจว่ารหัสพื้นที่นี้มีความสำคัญต่อความเร็ว
บางครั้ง

31
โปรดทราบว่าเทคนิคนี้ให้ตัวละครของคุณไม่ใช่รหัสจุดซึ่งหมายความว่าคุณอาจได้รับตัวแทน
Gabe

2
@ikh charAt ไม่ใช่ O (1) : เป็นเช่นนั้นได้อย่างไร รหัสสำหรับเป็นเพียงการทำString.charAt(int) value[index]ฉันคิดว่าคุณสับสนchatAt()กับสิ่งอื่นที่ให้คะแนนรหัสแก่คุณ
antak

209

สองตัวเลือก

for(int i = 0, n = s.length() ; i < n ; i++) { 
    char c = s.charAt(i); 
}

หรือ

for(char c : s.toCharArray()) {
    // process c
}

ครั้งแรกน่าจะเร็วกว่าแล้วที่สองน่าจะอ่านได้มากกว่า


26
บวกหนึ่งสำหรับการวาง s.length () ในนิพจน์การเริ่มต้น หากใครไม่ทราบว่าเพราะเหตุใดเพราะเป็นเพียงการประเมินเพียงครั้งเดียวหากวางไว้ในคำสั่งเลิกจ้างเป็น i <s.length () ดังนั้น s.length () จะถูกเรียกแต่ละครั้งที่มีการวนซ้ำ
เดนนิส

57
ฉันคิดว่าการปรับให้เหมาะสมกับคอมไพเลอร์ช่วยคุณได้
Rhyous

4
@Matthias คุณสามารถใช้ Disassembler คลาส Javap เพื่อดูว่ามีการหลีกเลี่ยงการเรียกซ้ำไปยัง s.length () ในนิพจน์การเลิกลูปอย่างแน่นอน โปรดทราบว่าในรหัส OP ที่ลงรายการบัญชีการเรียกไปยัง s.length () อยู่ในนิพจน์การเตรียมใช้งานดังนั้นความหมายของภาษาจึงรับประกันว่าจะถูกเรียกเพียงครั้งเดียว
prasopes

3
@prasopes โปรดทราบว่าการเพิ่มประสิทธิภาพของจาวาส่วนใหญ่เกิดขึ้นในรันไทม์ไม่ใช่ในไฟล์คลาส แม้ว่าคุณจะเห็นการโทรที่มีความยาวซ้ำ ๆ () ซึ่งไม่ได้ระบุว่ามีการลงโทษแบบรันไทม์ก็ตาม
Isaac

2
@ Lasse เหตุผลสมมุติสำหรับประสิทธิภาพ - รุ่นของคุณเรียกความยาว () วิธีการทำซ้ำทุกครั้งในขณะที่เดฟเรียกมันครั้งเดียวในการเริ่มต้น ที่กล่าวมาเป็นไปได้มากว่าเครื่องมือเพิ่มประสิทธิภาพ JIT ("ทันเวลาพอดี") จะปรับการโทรพิเศษให้ดีที่สุดดังนั้นจึงน่าจะเป็นเพียงความแตกต่างในการอ่านที่ไม่ได้รับจริง
Steve

90

สังเกตเทคนิคอื่น ๆ ที่อธิบายไว้ที่นี่ส่วนใหญ่หากคุณจัดการกับตัวละครนอก BMP (Unicode Basic Multilingual Plane ) นั่นคือจุดรหัสที่อยู่นอกช่วง u0000-uFFFF สิ่งนี้จะเกิดขึ้นได้ไม่บ่อยนักเนื่องจากรหัสจุดนอกนี้ส่วนใหญ่จะถูกกำหนดให้กับภาษาที่ตาย แต่มีอักขระที่มีประโยชน์อยู่ด้านนอกตัวอย่างเช่นบางจุดรหัสที่ใช้สำหรับสัญกรณ์คณิตศาสตร์และบางตัวใช้เพื่อเข้ารหัสชื่อที่เหมาะสมในภาษาจีน

ในกรณีนั้นรหัสของคุณจะเป็น:

String str = "....";
int offset = 0, strLen = str.length();
while (offset < strLen) {
  int curChar = str.codePointAt(offset);
  offset += Character.charCount(curChar);
  // do something with curChar
}

Character.charCount(int)วิธีการต้องใช้ Java 5+

ที่มา: http://mindprod.com/jgloss/codepoint.html


1
ฉันไม่เข้าใจว่าคุณจะใช้อะไรนอกจากเป็นเครื่องบินหลายภาษาขั้นพื้นฐานได้ที่นี่ curChar ยังคงเป็น 16 บิตอยู่ใช่ไหม
ศ. Falken ผิดสัญญา

2
คุณใช้ int เพื่อเก็บจุดรหัสทั้งหมดมิฉะนั้นอักขระแต่ละตัวจะเก็บคู่ตัวแทนตัวแทนสองคู่ที่กำหนดจุดรหัสเท่านั้น
sk.

1
ฉันคิดว่าฉันจำเป็นต้องอ่านข้อมูลเกี่ยวกับจุดโค้ดและคู่แทน ขอบคุณ!
ศ. Falken ผิดสัญญา

6
+1 เนื่องจากสิ่งนี้ดูเหมือนจะเป็นคำตอบเดียวที่ถูกต้องสำหรับตัวอักษร Unicode นอก BMP
Jason S

เขียนโค้ดเพื่อแสดงแนวคิดของการวนซ้ำ codepoints (ตรงข้ามกับตัวอักษร): gist.github.com/EmmanuelOga/ …
Emmanuel Oga

26

ฉันยอมรับว่า StringTokenizer เกินความเป็นจริงที่นี่ ที่จริงฉันลองทำตามคำแนะนำด้านบนแล้วใช้เวลา

การทดสอบของฉันค่อนข้างง่าย: สร้าง StringBuilder ที่มีประมาณหนึ่งล้านตัวอักษรแปลงเป็นสตริงและสำรวจแต่ละอักขระด้วย charAt () / หลังจากแปลงเป็นอาร์เรย์ถ่าน / ด้วย CharacterIterator พันครั้ง (แน่นอนว่าทำให้แน่ใจว่า ทำบางสิ่งบางอย่างบนสตริงเพื่อให้คอมไพเลอร์ไม่สามารถปรับห่วงทั้งหมด :-))

ผลลัพธ์ใน Powerbook 2.6 GHz ของฉัน (นั่นคือ mac :-)) และ JDK 1.5:

  • ทดสอบ 1: charAt + String -> 3138msec
  • ทดสอบ 2: สตริงที่แปลงเป็นอาร์เรย์ -> 9568msec
  • ทดสอบ 3: StringBuilder charAt -> 3536msec
  • ทดสอบ 4: CharacterIterator และ String -> 12151msec

เนื่องจากผลลัพธ์มีความแตกต่างอย่างมีนัยสำคัญวิธีที่ตรงไปตรงมาที่สุดก็ดูเหมือนจะเป็นวิธีที่เร็วที่สุด น่าสนใจ charAt () ของ StringBuilder ดูเหมือนจะช้ากว่าหนึ่งใน String เล็กน้อย

BTW ฉันแนะนำไม่ให้ใช้ CharacterIterator เพราะฉันพิจารณาว่าการใช้อักขระ '\ uFFFF' ในทางที่ผิดเป็นการ "สิ้นสุดการทำซ้ำ" แฮ็คที่น่ากลัวจริงๆ ในโครงการขนาดใหญ่มักมีผู้ชายสองคนที่ใช้การแฮ็กประเภทเดียวกันเพื่อวัตถุประสงค์ที่แตกต่างกันสองรายการและรหัสขัดข้องอย่างลึกลับ

นี่คือหนึ่งในการทดสอบ:

    int count = 1000;
    ...

    System.out.println("Test 1: charAt + String");
    long t = System.currentTimeMillis();
    int sum=0;
    for (int i=0; i<count; i++) {
        int len = str.length();
        for (int j=0; j<len; j++) {
            if (str.charAt(j) == 'b')
                sum = sum + 1;
        }
    }
    t = System.currentTimeMillis()-t;
    System.out.println("result: "+ sum + " after " + t + "msec");

1
นี่เป็นปัญหาเดียวกันที่สรุปไว้ที่นี่: stackoverflow.com/questions/196830/…
Emmanuel Oga

22

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

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

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

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

วิธีcodePoints()นี้ยังส่งคืนIntStreamเอกสารตาม:

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

ถ่านและจุดรหัสแตกต่างกันอย่างไร เป็นที่กล่าวถึงในนี้บทความ:

Unicode 3.1 เพิ่มอักขระเสริมซึ่งทำให้จำนวนอักขระรวมเกิน 216 ตัวที่สามารถแยกความแตกต่างด้วย 16 บิตcharเดียว ดังนั้นcharค่าจึงไม่มีการแมปแบบหนึ่งต่อหนึ่งกับหน่วยความหมายพื้นฐานใน Unicode อีกต่อไป ปรับปรุง JDK 5 เพื่อรองรับชุดอักขระที่มีขนาดใหญ่ขึ้น แทนที่จะเปลี่ยนคำจำกัดความของcharประเภทอักขระเสริมใหม่บางตัวจะถูกแทนด้วยคู่ตัวแทนสองcharค่า เพื่อลดความสับสนในการตั้งชื่อจุดรหัสจะถูกใช้เพื่ออ้างถึงหมายเลขที่แสดงถึงอักขระ Unicode เฉพาะรวมถึงตัวเสริม

ในที่สุดทำไมforEachOrderedและไม่forEach?

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

สำหรับความแตกต่างระหว่างตัวละคร, จุดโค้ด, glyph และกราฟตรวจสอบคำถามนี้


21

มีคลาสเฉพาะสำหรับเรื่องนี้:

import java.text.*;

final CharacterIterator it = new StringCharacterIterator(s);
for(char c = it.first(); c != CharacterIterator.DONE; c = it.next()) {
   // process c
   ...
}

7
ดูเหมือน overkill สำหรับสิ่งที่เรียบง่ายเหมือนวนซ้ำ char ที่ไม่เปลี่ยนรูป
ddimitrov

1
ฉันไม่เห็นสาเหตุที่เกินความจริง การวนซ้ำเป็นวิธี java-ish ที่สุดในการทำอะไร ... ซ้ำ StringCharacterIterator ถูกผูกไว้เพื่อใช้ประโยชน์จากการเปลี่ยนแปลงไม่ได้
บางครั้ง

2
เห็นด้วยกับ @ddimitrov - นี่คือ overkill เหตุผลเดียวที่ใช้ iterator คือการใช้ประโยชน์จาก foreach ซึ่งเป็นการง่ายกว่าที่จะ "เห็น" มากกว่าการวนซ้ำ หากคุณกำลังจะเขียนแบบดั้งเดิมสำหรับวงอยู่แล้วก็อาจใช้ charAt ()
Rob Gilliam

3
การใช้ตัววนซ้ำอักขระอาจเป็นวิธีเดียวที่ถูกต้องในการวนซ้ำอักขระเนื่องจาก Unicode ต้องการพื้นที่มากกว่าที่ Java charจัดเตรียมไว้ Java charมี 16 บิตและสามารถเก็บอักขระ Unicode ได้สูงสุด U + FFFF แต่ Unicode จะระบุอักขระได้สูงสุด U + 10FFFF การใช้ 16 บิตเพื่อเข้ารหัส Unicode ส่งผลให้มีการเข้ารหัสอักขระความยาวผันแปร คำตอบส่วนใหญ่ในหน้านี้ถือว่าการเข้ารหัส Java เป็นการเข้ารหัสความยาวคงที่ซึ่งไม่ถูกต้อง
เซเว่น

3
@ceving ดูเหมือนจะไม่ได้ว่า iterator ตัวละครจะช่วยคุณด้วยตัวละครที่ไม่ใช่ BMP: oracle.com/us/technologies/java/supplementary-142654.html
Bruno De Fraine

18

หากคุณมีGuavaอยู่ใน classpath ของคุณสิ่งต่อไปนี้เป็นทางเลือกที่อ่านง่าย Guava ยังมีการใช้งานรายการที่กำหนดเองที่สมเหตุสมผลสำหรับกรณีนี้ดังนั้นจึงไม่มีประสิทธิภาพ

for(char c : Lists.charactersOf(yourString)) {
    // Do whatever you want     
}

UPDATE: ตามที่ @Alex ระบุไว้ด้วย Java 8 ก็มีCharSequence#charsให้ใช้เช่นกัน แม้กระทั่งประเภทคือ IntStream ดังนั้นจึงสามารถแมปกับตัวอักษรเช่น:

yourString.chars()
        .mapToObj(c -> Character.valueOf((char) c))
        .forEach(c -> System.out.println(c)); // Or whatever you want

หากคุณต้องการทำอะไรซับซ้อนให้ไปกับ for loop + guava เนื่องจากคุณไม่สามารถกลายพันธุ์ตัวแปร (เช่น Integers และ Strings) ที่กำหนดไว้นอกขอบเขตของ forEach ภายใน forEach สิ่งที่อยู่ข้างในแต่ละคนก็ไม่สามารถโยนข้อยกเว้นที่ตรวจสอบได้ดังนั้นบางครั้งก็น่ารำคาญเช่นกัน
sabujp

13

หากคุณต้องการวนซ้ำคะแนนรหัสของString(ดูคำตอบนี้) วิธีที่สั้นลง / อ่านง่ายมากขึ้นคือการใช้CharSequence#codePointsวิธีการที่เพิ่มใน Java 8:

for(int c : string.codePoints().toArray()){
    ...
}

หรือใช้สตรีมโดยตรงแทน for loop:

string.codePoints().forEach(c -> ...);

นอกจากนี้ยังมีCharSequence#charsถ้าคุณต้องการกระแสของตัวละคร (แม้ว่าจะเป็นIntStreamเพราะไม่มีCharStream)


3

ฉันจะไม่ใช้StringTokenizerเนื่องจากเป็นหนึ่งในคลาสใน JDK ที่เป็นมรดก

javadoc พูดว่า:

StringTokenizerเป็นคลาสดั้งเดิมที่ถูกเก็บไว้เพื่อเหตุผลด้านความเข้ากันได้แม้ว่าการใช้งานจะไม่ได้รับการสนับสนุนในรหัสใหม่ ขอแนะนำให้ทุกคนที่แสวงหาฟังก์ชั่นนี้ใช้วิธีการแยกของStringหรือ java.util.regexแพคเกจแทน


String tokenizer เป็นวิธีที่ถูกต้องอย่างสมบูรณ์ (และมีประสิทธิภาพมากขึ้น) สำหรับการวนซ้ำโทเค็น (เช่นคำในประโยค) มันเป็น overkill สำหรับการวนซ้ำของตัวอักษร ฉันกำลังลดระดับความคิดเห็นของคุณเป็นความเข้าใจผิด
ddimitrov

3
ddimitrov: ฉันไม่ปฏิบัติตามวิธีชี้ให้เห็นว่าไม่แนะนำให้ใช้ StringTokenizer รวมถึงการเสนอราคาจาก JavaDoc ( java.sun.com/javase/6/docs/api/java/util/StringTokenizer.html ) ซึ่งระบุว่าเป็นเช่นนี้ ทำให้เข้าใจผิด เพิ่มขึ้นเพื่อชดเชย
Powerlord

1
ขอบคุณ Mr. Bemrose ... ฉันเข้าใจแล้วว่าการอ้างถึงบล็อกที่อ้างถึงควรจะชัดเจนซึ่งหนึ่งในนั้นน่าจะอนุมานได้ว่าการแก้ไขข้อบกพร่องที่ใช้งานจะไม่ถูกส่งไปยัง StringTokenizer
อลัน

2

หากคุณต้องการประสิทธิภาพคุณต้องทดสอบกับสภาพแวดล้อมของคุณ ไม่มีทางอื่น.

นี่คือตัวอย่างรหัส:

int tmp = 0;
String s = new String(new byte[64*1024]);
{
    long st = System.nanoTime();
    for(int i = 0, n = s.length(); i < n; i++) {
        tmp += s.charAt(i);
    }
    st = System.nanoTime() - st;
    System.out.println("1 " + st);
}

{
    long st = System.nanoTime();
    char[] ch = s.toCharArray();
    for(int i = 0, n = ch.length; i < n; i++) {
        tmp += ch[i];
    }
    st = System.nanoTime() - st;
    System.out.println("2 " + st);
}
{
    long st = System.nanoTime();
    for(char c : s.toCharArray()) {
        tmp += c;
    }
    st = System.nanoTime() - st;
    System.out.println("3 " + st);
}
System.out.println("" + tmp);

บนJava ออนไลน์ฉันจะได้รับ:

1 10349420
2 526130
3 484200
0

ใน Android x86 API 17 ฉันได้รับ:

1 9122107
2 13486911
3 12700778
0

0

ดูจาวา Tutorials: Strings

public class StringDemo {
    public static void main(String[] args) {
        String palindrome = "Dot saw I was Tod";
        int len = palindrome.length();
        char[] tempCharArray = new char[len];
        char[] charArray = new char[len];

        // put original string in an array of chars
        for (int i = 0; i < len; i++) {
            tempCharArray[i] = palindrome.charAt(i);
        } 

        // reverse array of chars
        for (int j = 0; j < len; j++) {
            charArray[j] = tempCharArray[len - 1 - j];
        }

        String reversePalindrome =  new String(charArray);
        System.out.println(reversePalindrome);
    }
}

ใส่ความยาวเข้าไปint lenและใช้forลูป


1
ฉันเริ่มรู้สึกสแปมนิดหน่อย ... ถ้ามีคำเช่นนี้ :) แต่วิธีนี้ยังมีปัญหาที่อธิบายไว้ที่นี่: ปัญหานี้มีปัญหาเดียวกันกับที่นี่: stackoverflow.com/questions/196830/…
Emmanuel Oga

0

StringTokenizer ไม่เหมาะที่จะแบ่งสตริงออกเป็นอักขระแต่ละตัวโดยสิ้นเชิง ด้วยการString#split()ที่คุณสามารถทำได้อย่างง่ายดายโดยใช้ regex ที่ตรงกับอะไรเช่น:

String[] theChars = str.split("|");

แต่ StringTokenizer ไม่ได้ใช้ regexes และไม่มีสตริงตัวคั่นที่คุณสามารถระบุได้ว่าจะตรงกับสิ่งใดระหว่างอักขระ มีเป็นหนึ่งในน้อยน่ารักตัดคุณสามารถใช้เพื่อให้บรรลุในสิ่งเดียวกัน: ใช้สตริงตัวเองเป็นตัวคั่นสตริง (ทำให้ตัวละครทุกตัวในนั้นคั่น) และมีมันกลับคั่น:

StringTokenizer st = new StringTokenizer(str, str, true);

อย่างไรก็ตามฉันพูดถึงตัวเลือกเหล่านี้เพื่อจุดประสงค์ในการยกเลิกเท่านั้น เทคนิคทั้งสองแตกสตริงดั้งเดิมเป็นสตริงอักขระหนึ่งตัวแทนที่จะใช้อักขระพื้นฐานและทั้งสองเกี่ยวข้องกับค่าใช้จ่ายจำนวนมากในรูปแบบของการสร้างวัตถุและการจัดการสตริง เปรียบเทียบกับการเรียก charAt () ใน for for loop ซึ่งไม่มีค่าใช้จ่ายใด ๆ เลย


0

อธิบายอย่างละเอียดเกี่ยวกับคำตอบนี้และคำตอบนี้

เหนือคำตอบที่ชี้ให้เห็นปัญหาของหลายโซลูชั่นที่นี่ซึ่งไม่สำทับด้วยค่าจุดรหัส - พวกเขาจะมีปัญหาใด ๆ กับตัวอักษรตัวแทน เอกสาร java ยังสรุปปัญหาที่นี่ด้วย (ดู "การแสดงอักขระ Unicode") อย่างไรก็ตามนี่คือรหัสบางส่วนที่ใช้ตัวอักษรตัวแทนบางตัวจากชุด Unicode เสริมและแปลงกลับเป็นสตริง โปรดทราบว่า. toChars () ส่งคืนอาร์เรย์ของตัวอักษร: หากคุณกำลังจัดการกับตัวแทนเสมือนคุณจะต้องมีตัวอักษรสองตัว รหัสนี้ควรใช้ได้กับอักขระ Unicode ใด ๆ

    String supplementary = "Some Supplementary: 𠜎𠜱𠝹𠱓";
    supplementary.codePoints().forEach(cp -> 
            System.out.print(new String(Character.toChars(cp))));

0

รหัสตัวอย่างนี้จะช่วยคุณออกไป!

import java.util.Comparator;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;

public class Solution {
    public static void main(String[] args) {
        HashMap<String, Integer> map = new HashMap<String, Integer>();
        map.put("a", 10);
        map.put("b", 30);
        map.put("c", 50);
        map.put("d", 40);
        map.put("e", 20);
        System.out.println(map);

        Map sortedMap = sortByValue(map);
        System.out.println(sortedMap);
    }

    public static Map sortByValue(Map unsortedMap) {
        Map sortedMap = new TreeMap(new ValueComparator(unsortedMap));
        sortedMap.putAll(unsortedMap);
        return sortedMap;
    }

}

class ValueComparator implements Comparator {
    Map map;

    public ValueComparator(Map map) {
        this.map = map;
    }

    public int compare(Object keyA, Object keyB) {
        Comparable valueA = (Comparable) map.get(keyA);
        Comparable valueB = (Comparable) map.get(keyB);
        return valueB.compareTo(valueA);
    }
}

0

ดังนั้นโดยทั่วไปมีสองวิธีในการวนซ้ำผ่านสตริงใน java ซึ่งได้รับการตอบแล้วโดยคนหลายคนที่นี่ในหัวข้อนี้เพียงแค่เพิ่มรุ่นของฉันมันก่อนใช้

String s = sc.next() // assuming scanner class is defined above
for(int i=0; i<s.length; i++){
     s.charAt(i)   // This being the first way and is a constant time operation will hardly add any overhead
  }

char[] str = new char[10];
str = s.toCharArray() // this is another way of doing so and it takes O(n) amount of time for copying contents from your string class to character array

หากประสิทธิภาพการทำงานมีความเสี่ยงแล้วฉันจะแนะนำให้ใช้ครั้งแรกในเวลาคงที่ถ้าไม่ไปกับคนที่สองทำให้งานของคุณง่ายขึ้นพิจารณาความไม่เปลี่ยนแปลงกับคลาสสตริงใน java

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