Сортировать карту по некоторым правилам - PullRequest
1 голос
/ 25 декабря 2011

У меня есть карта, которую я хочу отсортировать в соответствии с некоторыми правилами:

  1. Сортировка карты в алфавитном порядке (от A до Z) по значениям, а не по ключам.
  2. Игнорировать Чувствительность к регистру значений при сортировке.
  3. Учитывайте повторяющиеся слова (слова, имеющие точные буквы: орфография и регистр).
  4. Сортировать буквенно-цифровые слова вправо ( Cbc2ee должно появиться до Cbc100ee ).
  5. Обрабатывать неанглийские слова ( область должна появляться в словах, начинающихся с буквы "a", но на самом деле она появляется после слов, начинающихся с буквы "z", с учетом другой буквы).

Я думаю, все, что я хочу, логично. Я смог выполнить пункты 1, 2 и 3 с помощью этого кода:

public <K, V extends Comparable<? super V>> LinkedHashMap<K, V> sortMapByValues( Map<K, V> map ) {
    SortedSet<Map.Entry<K, V>> sortedEntries = new TreeSet<Map.Entry<K, V>>(
        new Comparator<Map.Entry<K, V>>() {
            @Override 
            public int compare( Map.Entry<K, V> e1, Map.Entry<K, V> e2 ) {
                String a = (String)e1.getValue();
                String b = (String)e2.getValue();

                int diff = a.compareToIgnoreCase( b );

                if (diff == 0) 
                    diff = a.compareTo(b);  

                return diff != 0 ? diff : 1;  // Special fix to preserve words with similar spelling.
            }
        }
    );

    sortedEntries.addAll( map.entrySet() );

    LinkedHashMap<K, V> sortedMap = new LinkedHashMap<K, V>();

    for( Map.Entry<K, V> sortedEntry : sortedEntries )
        sortedMap.put( sortedEntry.getKey(), sortedEntry.getValue() );

    return sortedMap;
}

Точка (4) Я нашел скрипт для него, но не смог объединить его с моим кодом: http://www.davekoelle.com/alphanum.html

Точка (5) также я нашел скрипт для него, но я не смог объединить его с моим кодом: http://www.javapractices.com/topic/TopicAction.do?Id=207

Поскольку эти точки будут влиять на метод сравнения (...). Кто-нибудь может мне помочь с этим?

1 Ответ

1 голос
/ 26 декабря 2011

Пара точек ...

Подпись метода должна быть:

public static <K, V> Map<K, V> sortMapByValues(Map<K, V> map)

Примечание: - Удаление привязки к Comparable, потому что вы сравниваете toString() значений карты, а не самих значений - спецификация абстрактного типа Map<...>, а не конкретного LinkedHashMap, в соответствии с хорошими рекомендациями по проектированию - static, потому что это не меняет состояние - это «просто код»

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

Вот код, который должен делать то, что вы хотите:

public static <K, V> Map<K, V> sortMapByValues(Map<K, V> map) {
    SortedSet<Map.Entry<K, V>> sortedEntries = new TreeSet<Map.Entry<K, V>>(new Comparator<Map.Entry<K, V>>() {
        public int compare(Map.Entry<K, V> e1, Map.Entry<K, V> e2) {
            String aRaw = e1.getValue().toString();
            String bRaw = e2.getValue().toString();
            String a = standardize(aRaw);
            String b = standardize(bRaw);

            // Check for hex
            try
            {
                Integer ai = Integer.parseInt(a, 16);
                Integer bi = Integer.parseInt(b, 16);
                int diff = ai.compareTo(bi);
                if (diff != 0)
                    return diff;
            }
            catch (NumberFormatException ignore)
            {
            }

            int diff = a.compareTo(b);
            if (diff != 0)
                return diff;
            return aRaw.compareTo(bRaw);
        }

        /** This method removes all accent (diacritic) marks and changes to lower case */
        String standardize(String input) {
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < input.length(); i++) {
                char c = input.charAt(i);
                sb.append(Normalizer.normalize(c + "", Form.NFD).replaceAll("\\p{InCombiningDiacriticalMarks}+", ""));
            }
            return sb.toString().toLowerCase();
        }
    });

    // The rest is your code left as it was, cos it's fine
    sortedEntries.addAll(map.entrySet());

    LinkedHashMap<K, V> sortedMap = new LinkedHashMap<K, V>();

    for (Map.Entry<K, V> sortedEntry : sortedEntries)
        sortedMap.put(sortedEntry.getKey(), sortedEntry.getValue());

    return sortedMap;
}

Вот код теста:

public static void main(String[] args) {
    Map<String, String> map = new HashMap<String, String>();
    map.put("a", "CC96");
    map.put("b", "CC97");
    map.put("c", "CC102");
    map.put("d", "CC103");
    map.put("e", "aabbcc");
    map.put("f", "aabbCC");
    map.put("g", "atabends");
    map.put("h", "aaBBcc");
    map.put("i", "AABBcc");
    map.put("j", "aabbcc");
    map.put("k", "Cc102");
    map.put("l", "baldmöglichst");
    map.put("m", "bar");
    map.put("n", "barfuss");
    map.put("o", "barfuß");
    map.put("p", "spätabends");
    map.put("q", "ätabends");
    map.put("r", "azebra");

    System.out.println(sortMapByValues(map).toString()
        .replaceAll(", ", "\r").replaceAll("(\\{|\\})", ""));
}

Выход:

a=CC96
b=CC97
c=CC102
k=Cc102
d=CC103
i=AABBcc
h=aaBBcc
f=aabbCC
e=aabbcc
g=atabends
q=ätabends
r=azebra
l=baldmöglichst
m=bar
n=barfuss
o=barfuß
p=spätabends
...