2014-11-27 3 views
4

У меня проблема с сортировкой строк, которые включают целые числа. Если я использую следующий код я получаю сортировки, как: 1some, 2some, 20some, 21some, 3 some, некоторыеКак сортировать буквенно-цифровую строку

Однако я хочу это сортируется как: 1some, 2some, 3 some, 20some, 21some, некоторые

Как я могу это сделать?

Спасибо!

Collections.sort(selectedNodes, 
    new Comparator<DefaultMutableTreeNode>() { 
    @Override 
    public int compare(DefaultMutableTreeNode o1, 
     DefaultMutableTreeNode o2) { 
     return o1.getUserObject().toString() 
      .compareTo(o2.getUserObject().toString()); 
    } 
    }); 
+0

вы должны разделить строки в двух первых; другая часть является целой частью, а другая - частью строки. затем сначала сравните целые числа - если целые числа не равны, строка, которая должна появиться первой, - это та, которая имеет меньшую целую часть. Если они равны, строка, которая должна отображаться первой, - это строка со * строкой в ​​алфавитном порядке. –

+0

Разделите целое число из строки и сравните его перед сравнением остальной части строки. Если он всегда начинается с уникальных целых чисел, вы можете даже пропустить остальную часть строки. – Magnilex

+0

Строка может быть в любом формате - например: other 1, other 2, 1 some 2 other 3, ... Я думаю, что было бы сложно разбить строку и сравнить только целую часть. – Thaven

ответ

6

Вот самодостаточным пример того, как это сделать (не особо оптимизированная):

final Pattern p = Pattern.compile("^\\d+"); 
String[] examples = { 
    "1some", "2some", "20some", "21some", "3some", "some", "1abc", "abc" 
}; 
Comparator<String> c = new Comparator<String>() { 
    @Override 
    public int compare(String object1, String object2) { 
     Matcher m = p.matcher(object1); 
     Integer number1 = null; 
     if (!m.find()) { 
      return object1.compareTo(object2); 
     } 
     else { 
      Integer number2 = null; 
      number1 = Integer.parseInt(m.group()); 
      m = p.matcher(object2); 
      if (!m.find()) { 
       return object1.compareTo(object2); 
      } 
      else { 
       number2 = Integer.parseInt(m.group()); 
       int comparison = number1.compareTo(number2); 
       if (comparison != 0) { 
        return comparison; 
       } 
       else { 
        return object1.compareTo(object2); 
       } 
      } 
     } 
    } 
}; 
List<String> examplesList = new ArrayList<String>(Arrays.asList(examples)); 
Collections.sort(examplesList, c); 
System.out.println(examplesList); 

Выход

[1abc, 1some, 2some, 3some, 20some, 21some, abc, some] 

Объяснение

  • В примере используется константа Pattern для определения того, находится ли число в исходной позиции String.
  • Если нет в первом String, он сравнивает его как со вторым.
  • Если он присутствует в первом, он проверяет второй.
  • Если нет в секунду, он сравнивает два String с как есть, опять-таки
  • Если он присутствует в обоих, он сравнивает Integer с вместо целых String с, следовательно, в результате чего численного сравнения, а не лексикографическом один
  • Если число сравнивать одинаковым, она восходит к лексикографическому сравнению целых String с (спасибо MihaiC за пятнистость этого)
+0

хорошее решение, но оно сортируется по номерам сначала, а затем по тексту. так что если исходный массив имеет контент, такой как «1some», «2some», «20some», «21some», «3some», «some», «abc». Он положил бы abc в конце – MihaiC

+0

@MihaiC только что понял вашу точку. На самом деле он будет помещать '' abc'' ** перед ** '" some "'. Хотя оба в конце, так как в лексикографическом сравнении приоритеты цифр над алфавитными символами. – Mena

+0

Я знаю, мне просто интересно. я думаю, что правильное представление должно быть «abc», а затем «1some» «2some» и т. д., конечно, номера сортируются сначала в любом компараторе, но все же интересный вопрос – MihaiC

2

Ваше решение лежит в The Alphanum Algorithm и вы можете реализовать как this

+0

Это хорошее решение, но, возможно, слишком сложное для этого конкретного случая, когда числовая часть (по-видимому) всегда находится перед строкой. Изменить - Тейвен сказал, что цифры могут быть в любом порядке; таким образом, отказаться от этого комментария –

+0

@OlaviMustanoja OP утверждает, что строки могут быть в любом формате. – spoko

+0

@spoko заметил это за 5 секунд до вашего комментария: D –

0

Вы должны реализовать свой собственный Comparator, чтобы сделать этот вид пользовательской сортировки. По умолчанию метод String.compareTo() сортирует числа перед символами. Когда 0 в 20some сравнивается с s в 3some, то 0 имеет более высокий приоритет сортировки, и поэтому все слово сортируется в первую очередь.
Что вам нужно сделать, так это: попытайтесь разделить строки на число и часть символа. Это сложная задача, так как эти String s могут состоять из многих из этих частей (или не так ли?). Вы можете использовать такие алгоритмы, как Alphanum, которые Муртаза уже вам показал.
Если вы хотите реализовать его самостоятельно, вы можете проверить, где заканчивается номер. Затем проанализируйте его до int с помощью Integer.parse(). Сравните int частей, если они существуют в обоих String s, а затем сравните остальные. Хорошо, что это не может быть самым профессиональным решением, но, как новичок, вы можете сами попробовать эти вещи сами изучить его.

-3
String [] str = new String[]{"1some", "2some", "20some", "21some", "3some", "some"}; 
    List<String> list = Arrays.asList(str); 

    Collections.sort(list, String.CASE_INSENSITIVE_ORDER); 
    System.out.println(list); 
0

Вы не можете использовать по умолчанию строки CompareTo() вместо нужно сравнить Строки, следуя приведенному ниже алгоритму.

  1. Loop через первый и второй символ Струнный по характеру и получить кусок всех строк или чисел
  2. Проверьте куски являются числами или строками
  3. Если номера сортировать численно еще использовать Струнный СотрагеТо()

Повторите шаги.

0

Сначала сделайте буквенно-цифровой компаратор, разделяющий строку в строковых или целых частях.

public class AlphaNumericalComparator implements Comparator<String> { 
    @Override 
    public int compare(String o1, String o2) { 
     List<Object> parts1 = partsOf(o1); 
     List<Object> parts2 = partsOf(o2); 
     while (!parts1.isEmpty() && !parts2.isEmpty()) { 
      Object part1 = parts1.remove(0); 
      Object part2 = parts2.remove(0); 
      int cmp = 0; 
      if (part1 instanceof Integer && part2 instanceof Integer) { 
       cmp = Integer.compare((Integer)part1, (Integer)part2); 
      } else if (part1 instanceof String && part2 instanceof String) { 
       cmp = ((String) part1).compareTo((String) part2); 
      } else { 
       cmp = part1 instanceof String ? 1 : -1; // XXXa > XXX1 
      } 
      if (cmp != 0) { 
       return cmp; 
      } 
     } 
     if (parts1.isEmpty() && parts2.isEmpty()) { 
      return 0; 
     } 
     return parts1.isEmpty() ? -1 : 1; 
    } 

    private List<Object> partsOf(String s) { 
     List<Object> parts = new LinkedList<>(); 
     int pos0 = 0; 
     int pos = 0; 
     boolean wasDigit = false; 
     while (true) { 
      if (pos >= s.length() 
        || Character.isDigit(s.charAt(pos)) != wasDigit) { 
       if (pos > pos0) { 
        String part = s.substring(pos0, pos); 
        parts.add(wasDigit? Integer.valueOf(part) : part); 
        pos0 = pos; 
       } 
       if (pos >= s.length()) { 
        break; 
       } 
       wasDigit = !wasDigit; 
      } 
      ++pos; 
     } 
     return parts; 
    } 
}; 

Затем использовать этот компаратор в собственных один, в Java 8, вы можете просто использовать статические методы компаратора.

0

Вы можете сделать ядро ​​его в одной строке, используя регулярное выражение для извлечения числовой части:

Collections.sort(selectedNodes, new Comparator<DefaultMutableTreeNode>() { 
    @Override 
    public int compare(DefaultMutableTreeNode o1, 
     DefaultMutableTreeNode o2) { 
     return Integer.psrseInt(o1.getUserObject().toString().replaceAll("\\D", "")) - 
      Integer.psrseInt(o2.getUserObject().toString().replaceAll("\\D", "")); 
    } 
}); 
Смежные вопросы