ما هي الطريقة الأسهل/الأفضل/الأصح للتكرار من خلال أحرف السلسلة في Java؟

StackOverflow https://stackoverflow.com/questions/196830

سؤال

StringTokenizer؟تحويل String إلى أ char[] وتكرر على ذلك؟شيء آخر؟

هل كانت مفيدة؟

المحلول

ويمكنني استخدام لحلقة لتكرار سلسلة واستخدام charAt() للحصول على كل حرف لفحصه. منذ يتم تنفيذ سلسلة مع مجموعة، وطريقة charAt() هو عملية مستمرة الوقت.

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

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

وهذا ما أود القيام به. يبدو أسهل بالنسبة لي.

وبقدر ما يذهب صحة، وأنا لا أعتقد أن وجود هنا. وكلها ترتكز على أسلوب حياتك الشخصية.

نصائح أخرى

وخياران

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

أو

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

والأول هو الأرجح أسرع، ثم 2 وربما أكثر قابلية للقراءة.

ملاحظة معظم التقنيات الأخرى الموصوفة هنا تنهار إذا كنت تتعامل مع شخصيات من خارج BMP (يونيكود <لأ href = "http://en.wikipedia.org/wiki/Mapping_of_Unicode_character_planes#Basic_Multilingual_Plane" يختلط = " noreferrer "> متعدد اللغات الأساسية الطائرة )، أي نقاط كود التي هي خارج 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) يتطلب جافا 5 +.

المصدر: http://mindprod.com/jgloss/codepoint.html

أوافق على أن StringTokenizer مبالغة هنا.في الواقع لقد جربت الاقتراحات المذكورة أعلاه وأخذت الوقت.

كان اختباري بسيطًا إلى حد ما:قم بإنشاء StringBuilder بحوالي مليون حرف، وقم بتحويله إلى سلسلة، واجتاز كل منها باستخدام charAt() / بعد التحويل إلى مصفوفة char / باستخدام CharacterIterator ألف مرة (بالطبع تأكد من القيام بشيء ما على السلسلة حتى لا يستطيع المترجم تحسين الحلقة بأكملها :-) ).

النتيجة على جهاز Powerbook بسرعة 2.6 جيجا هرتز (هذا جهاز Mac :-)) وJDK 1.5:

  • الاختبار 1:حرف + سلسلة -> 3138 مللي ثانية
  • الاختبار 2:تم تحويل السلسلة إلى مصفوفة -> 9568 مللي ثانية
  • الاختبار 3:StringBuilder charAt -> 3536 مللي ثانية
  • الاختبار 4:مكرر الشخصية والسلسلة -> 12151 مللي ثانية

نظرًا لاختلاف النتائج بشكل كبير، يبدو أن الطريقة الأكثر مباشرة هي الأسرع أيضًا.ومن المثير للاهتمام أن charAt() الخاص بـ StringBuilder يبدو أبطأ قليلاً من String.

راجع للشغل أقترح عدم استخدام 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");

وهناك بعض فصول مخصصة لذلك:

import java.text.*;

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

إذا كان لديك الجوافة على CLASSPATH الخاص بك، وفيما يلي بديل قراءة جميلة . الجوافة لديه حتى تنفيذ قائمة مخصصة معقول إلى حد ما لهذه الحالة، وحتى هذا لا ينبغي أن يكون غير فعال.

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

وUPDATE: كما لوحظAlex، مع جافا 8 هناك أيضا <لأ href = "https://docs.oracle.com/javase/8/docs/api/java/lang/CharSequence.html#chars--" يختلط = "نوفولو"> CharSequence#chars للاستخدام. حتى نوع هو IntStream، بحيث يمكن تعيينها إلى حرف مثل:

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

في جافا 8 يمكننا حلها على النحو التالي:

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

الطريقة chars() تُرجع ملفًا IntStream كما ذكر في وثيقة:

إرجاع تيار من int Zero-Extending القيم Char من هذا التسلسل.يتم تمرير أي char الذي يقوم بتعيين نقطة رمز بديلة من خلال دون تفسير.إذا تم تحور التسلسل أثناء قراءة الدفق ، فإن النتيجة غير محددة.

طريقة codePoints() يعود أيضًا IntStream حسب الوثيقة:

يُرجع دفقًا من قيم نقاط التعليمات البرمجية من هذا التسلسل.يتم الجمع بين أي أزواج بديلة تمت مواجهتها في التسلسل كما لو كانت بواسطة الحرف.يتم تمديد أي وحدات رمز أخرى ، بما في ذلك أحرف BMP العادية ، والبدائل غير المقيدة ، ووحدات التعليمات البرمجية غير المحددة ، صفراً إلى قيم INT التي يتم تمريرها بعد ذلك إلى الدفق.

كيف يختلف الحرف ونقطة الكود؟ كما ذكر في هذا شرط:

وأضاف Unicode 3.1 أحرفًا تكميلية ، مما يجلب العدد الإجمالي للأحرف إلى أكثر من 216 حرفًا يمكن تمييزه بواسطة 16 بت واحد char.ولذلك، أ char لم تعد القيمة لديها رسم خرائط فردي للوحدة الدلالية الأساسية في Unicode.تم تحديث JDK 5 لدعم مجموعة أكبر من قيم الأحرف.بدلا من تغيير تعريف char النوع ، يتم تمثيل بعض الشخصيات التكميلية الجديدة بزوج بديل من اثنين char قيم.لتقليل الارتباك التسمية ، سيتم استخدام نقطة رمز للإشارة إلى الرقم الذي يمثل حرف Unicode معين ، بما في ذلك تلك التكميلية.

وأخيرا لماذا forEachOrdered و لا forEach ?

سلوك forEach هو غير حتمي بشكل صريح حيث forEachOrdered ينفذ إجراءً لكل عنصر من عناصر هذا الدفق، في ملف مواجهة ترتيب الدفق إذا كان الدفق لديه ترتيب لقاء محدد.لذا forEach لا يضمن الحفاظ على الطلب.تحقق من هذا أيضًا سؤال للمزيد من.

ل الفرق بين الحرف ونقطة الكود والحرف الرسومي والحرف افحص هذا سؤال.

إذا كنت بحاجة إلى التكرار من خلال نقاط التعليمات البرمجية الخاصة بـ a String (انظر الى هذا إجابة) الطريقة الأقصر/الأكثر قابلية للقراءة هي استخدام ملف CharSequence#codePoints تمت إضافة الطريقة في Java 8:

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

أو استخدام الدفق مباشرةً بدلاً من حلقة for:

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

يوجد ايضا CharSequence#chars إذا كنت تريد دفقًا من الشخصيات (على الرغم من أنه ملف IntStream, ، لأنه لا يوجد CharStream).

وأنا لن تستخدم StringTokenizer كما أنها واحدة من الفئات في JDK هذا الإرث.

ووجافادوك يقول:

<اقتباس فقرة>   

وStringTokenizer هي فئة القديمة التي   يتم الاحتفاظ لأسباب التوافق   على الرغم من أن استخدامه لا ينصح في الجديدة   الشفرة. فمن المستحسن أن أي شخص   تسعى هذه الوظيفة استخدام   طريقة تقسيم من String أو   حزمة java.util.regex بدلا من ذلك.

إذا كنت تحتاج إلى أداء، فإنك على يجب اختبار على بيئتك. أي وسيلة أخرى.

وهنا مثال التعليمة البرمجية:

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

في جافا على الانترنت أحصل على:

1 10349420
2 526130
3 484200
0

في الروبوت إلى x86 API 17 أحصل على:

1 9122107
2 13486911
3 12700778
0

جافا دروس: الاوتار .

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 حلقة.

وStringTokenizer لا يصلح تماما لهذه المهمة من كسر سلسلة إلى شخصياتها الفردية. مع String#split() يمكنك القيام بذلك بسهولة باستخدام التعابير المنطقية يطابق شيئا، منها مثلا:

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

ولكن StringTokenizer لا تستخدم regexes، وليس هناك سلسلة محدد يمكنك تحديد من شأنها أن تتطابق مع أي شيء بين الأحرف. هناك <م> هو واحد الإختراق لطيف قليلا يمكنك استخدامها لتحقيق نفس الشيء: استخدام السلسلة نفسها على أنها سلسلة محدد (صنع كل حرف فيه محدد)، ولها أن تعيد المحددات:

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

ومع ذلك، أود فقط أن أذكر هذه الخيارات لغرض صرف النظر عنها. كلا تقنيات كسر السلسلة الأصلية إلى سلاسل حرف واحد بدلا من الأوليات شار، وكلاهما ينطوي على قدر كبير من النفقات العامة في شكل إنشاء كائن والتلاعب السلسلة. قارن ذلك إلى الدعوة charAt () في لحلقة، التي تتحمل تكاد تنعدم في سماء المنطقة.

وتعليقا على هذه الإجابة و <وأ href = "https://stackoverflow.com/a/27796856/99717 "> هذه الإجابة .

وفوق إجابات يشيرون إلى مشكلة العديد من الحلول هنا والتي لا تكرار من حيث القيمة نقطة رمز - سيكون لديهم مشكلة مع أي <لأ href = "https://en.wikipedia.org/wiki/Universal_Character_Set_characters #Surrogates "يختلط =" نوفولو noreferrer "> بديل حرف . مستندات جافا أيضا الخطوط العريضة لقضية هنا (انظر "التمثيل يونيكود الأحرف"). على أية حال، إليك بعض التعليمات البرمجية التي تستخدم بعض حرف البديلة الفعلية من مجموعة يونيكود التكميلي، ويحولهم <م> العودة إلى سلسلة. لاحظ أن .toChars () بإرجاع مجموعة من حرف: إذا كنت تتعامل مع عملائها، سيكون لديك بالضرورة اثنين حرف. يجب أن تعمل هذه التعليمات البرمجية ل <م> أي حرف Unicode.

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

وهذا مثال التعليمة البرمجية سوف تساعدك على الخروج!

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);
    }
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top