2013-09-21 18 views
1

Я получил строку:Самый эффективный способ реализовать это?

00122334455667788990875645346787659870984780... 

выше данного размера строка всегда будет четным. Мне нужно реализовать метод, который вернет Arraylist String, где каждый элемент будет содержать 2 символа. например, для выше строк:

1st position of arraylist will contain: 00 
2nd: 12 
3rd: 23 
... 

Я пытался реализовать себя, это то, как мои функции выглядят следующим образом:

private static ArrayList<String> getArrayListFrom(String data) { 
    if(data.length()%2==0){ 
     ArrayList<String> aList = new ArrayList<String>(); 
     char[] dArray = data.toCharArray(); 
     //logic here. 
     for(int i = 0; i < dArray.length + 2; i = i+2){ 
      if(i != 0){ 
       aList.add(dArray[i-2]+""+dArray[i-1]); 
      } 
     } 
     return aList; 
    }else{ 
     System.out.println("Invalid data."); 
     return null; 
    } 
} 

This URL показывает, что простая итерация является более эффективной в данном случае. вы, ребята, согласны?

+0

Каков ваш критерий эффективности? Представление? Лаконичность? – assylias

+0

Он должен иметь возможность обрабатывать большую строку как это как можно скорее. :-) – dreamer

ответ

10

Вы можете сделать это с помощью одного раскола (ну, это не может быть наиболее эффективным во время выполнения, но это краткое, меньший код для записи):

String[] arr = str.split("(?<=\\G..)"); 

А затем получить List<String> используя Arrays#asList() метод ,

Шаблон регулярного выражения распадается на пустое место, которому предшествуют 2 символа - .., но игнорирует символ, уже учтенный в предыдущем матче - \\G. Анкер \\G соответствует в том месте, где закончился предыдущий матч.

String str = "00122334455667788990875645346787659870984780"; 
String[] arr = str.split("(?<=\\G..)"); 

System.out.println(Arrays.asList(arr)); 

печатает:

[00, 12, 23, 34, 45, 56, 67, 78, 89, 90, 87, 56, 45, 34, 67, 87, 65, 98, 70, 98, 47, 80] 

Вот как разделение делается на вашей строке:

" 00  1 2  2334455667788990875645346787659870984780" (whitespaces represent empty string) 
//  |  |  | 
// split, no-split, split -> gives 12 
// | | |  | 
// \ /\ /
// gives 00 as the preceding two characters are `1` and `0`. 
//   but 0 is already considered for the previous empty string 

Ссылка:


Если производительность выполнения является проблемой, то вы можете пойти с простым зацикливанием:

String str = "00122334455667788990875645346787659870984780"; 
List<String> list = new ArrayList<String>(); 
for (int i = 0; i < str.length(); i += 2) { 
    list.add(str.substring(i, i + 2)); 
} 
System.out.println(list); 

Но вы можете проверить для себя, является ли регулярное выражение раскол действительно узкое место производительности для большой струны, и сравнивайте их оба.


Я сравнивал оба метода - разделение и цикл. И так как ожидаемый цикл почти в 4-5 раз эффективнее, чем сплит для строки длины, скажем 1000.

public static void usingSplit(String str) { 
    String[] arr = str.split("(?<=\\G..)"); 
    List<String> list = Arrays.asList(arr); 
} 

public static void usingLoop(String str) { 
    List<String> list = new ArrayList<String>(); 
    for (int i = 0; i < str.length(); i += 2) { 
     list.add(str.substring(i, i + 2)); 
    } 
} 

// Warm up JVM 
    for (int i = 0; i < 1000000; ++i) { 
     usingSplit(str); 
    } 
    for (int j = 0; j < 1000000; j++) { 
     usingLoop(str); 
    } 

    long nano = System.nanoTime(); 
    for (int i = 0; i < 1000000; ++i) { 
     usingSplit(str); 
    } 
    System.out.println("Time with usingSplit(): " + (System.nanoTime() - nano) * 1.0/Math.pow(10, 9) + " Seconds"); 

    nano = System.nanoTime(); 
    for (int j = 0; j < 1000000; j++) { 
     usingLoop(str); 
    } 
    System.out.println("Time with usingLoop(): " + (System.nanoTime() - nano) * 1.0/Math.pow(10, 9) + " Seconds"); 

Выход на несколько последовательных прогонов:

Run 1: 
Time with usingSplit(): 34.391315143 Seconds 
Time with usingLoop(): 7.515221612 Seconds 

Run 2: 
Time with usingSplit(): 33.41518869 Seconds 
Time with usingLoop(): 7.868896218 Seconds 

Если кто-то думает, что тест результат является ошибочным, то, пожалуйста, запишите его в комментариях.

+0

Регулярные выражения интерпретируются и так неэффективны. –

+0

@AlexeiKaigorodov. Ну, иногда задача действительно должна выполняться с использованием регулярного выражения. Итерация по строке также является опцией. Но вы просто пишете меньше кодов с помощью split. И это не так сильно неэффективно, как вы предполагаете. –

+0

@RohitJain (смиренно) я упомянул URL-адрес, который предполагает, что в некоторых случаях простая итерация более эффективна. Как вы думаете ? – dreamer

6
ArrayList<String> aList = new ArrayList<String>(); 
    //logic here. 
    for(int i = 0; i < data.length(); i+=2){ 
     aList.add(data.subString(i, i+2)); 
    } 
    return aList; 
+2

Для лучшей производительности, особенно если строка очень длинная, предварительно запустите список: 'new ArrayList <> (data.length/2);' – assylias

+1

Вероятно, используя 'Vector', поскольку OP говорит, что он использует J2ME. – bsd

+0

@bsd Сначала попробую реализовать его с помощью Vector. – dreamer

Смежные вопросы