Чому EnumMap не сортується на Java?


9

EnumMap<K extends Enum<K>, V> в Java чітко впорядковано за визначенням асоційованого enum, як ви також можете бачити в javadoc:

Карти Enum підтримуються в природному порядку їхніх ключів (порядку, в якому оголошуються константи enum). Це знаходить своє відображення в Ітератор повернутого видом колекцій ( keySet(), entrySet()і values()).

Що мені потрібно - це SortedMapвикористання enum як ключового типу. Я хочу використовувати такі методи , як headMap()або firstKey(), але я хочу , щоб отримати прибуток від доданої продуктивності процесора + пам'яті EnumMapс. А TreeMapзвучить як занадто багато накладних витрат тут.

Запитання : це лише було пропущено у впровадженні, це лінь (походить від AbstractMap) чи є вагома причина, чому EnumMapце не так SortedMap?



@MohammedDeifallah Це зовсім інше, у нього немає ключів ... Ви мали на увазі TreeMap?
deHaar

3
Мені вдалося знайти це питання для openjdk. Це з 2005 року, але все ще є відкритим / невирішеним. Я припускаю, що немає жодної «вагомої причини» для цього не реалізуватися.
Амонгален

1
Дякую за дійсно швидкі відповіді, я додав, що я знаходжу TreeMap занадто багато накладних, плюс O (log n) для запитів. Але моє питання, звичайно, також враховується для EnumSet і SortedSet, тієї ж проблеми.
rawcode

@Amongalen: ваша відповідь кваліфікується як відповідь на моє запитання, навіть якщо вона не відповідає першопричині, окрім "Oracle не запотіває турботу". Навіть google не знайшов згадувану вами проблему OpenJDK, тому принаймні це допоможе іншим із тією ж проблемою.
rawcode

Відповіді:


3

Це не дасть відповіді на ваше основне запитання (оскільки відповіді мають лише оригінальні дизайнери), але один із підходів, який я розглядав, був для вас, щоб реалізувати його самостійно. Намагаючись зробити SortedMapреалізацію на основі EnumMap, я придумав наступний клас.

Це, безумовно, швидка та брудна реалізація (зауважте, що вона не повністю відповідає SortedMap- тому що вимоги до перегляду не виконані), але якщо вона потрібна , ви можете її покращити:

class SortedEnumMap<K extends Enum<K>, V> 
    extends EnumMap<K, V> 
    implements SortedMap<K, V> {

    private Class<K> enumClass;
    private K[] values;

    public SortedEnumMap(Class<K> keyType) {
        super(keyType);
        this.values = keyType.getEnumConstants();
        this.enumClass = keyType;

        if (this.values.length == 0) {
            throw new IllegalArgumentException("Empty values");
        }
    }

    @Override
    public Comparator<? super K> comparator() {
        return Comparator.comparingInt(K::ordinal);
    }

    @Override
    public SortedMap<K, V> subMap(K fromKey, K toKey) {
        List<K> keys = Arrays.stream(this.values)
                .dropWhile(k -> k.ordinal() < fromKey.ordinal())
                .takeWhile(k -> k.ordinal() < toKey.ordinal())
                .collect(Collectors.toList());

        return this.forKeys(keys);
    }

    @Override
    public SortedMap<K, V> headMap(K toKey) {
        List<K> keys = new ArrayList<>();

        for (K k : this.values) {
            if (k.ordinal() < toKey.ordinal()) {
                keys.add(k);
            } else {
                break;
            }
        }

        return this.forKeys(keys);
    }

    @Override
    public SortedMap<K, V> tailMap(K fromKey) {
        List<K> keys = new ArrayList<>();

        for (K k : this.values) {
            if (k.ordinal() >= fromKey.ordinal()) {
                keys.add(k);
            }
        }

        return this.forKeys(keys);
    }

    //Returned map is NOT a "view" or the current one
    private SortedEnumMap<K, V> forKeys(List<K> keys) {
        SortedEnumMap<K, V> n = new SortedEnumMap<>(this.enumClass);
        keys.forEach(key -> n.put(key, super.get(key)));

        return n;
    }

    @Override
    public K firstKey() {
        return this.values[0];
    }

    @Override
    public K lastKey() {
        return this.values[this.values.length - 1];
    }
}

І для швидкого тестування (помилок ще не знайдено):

SortedMap<Month, Integer> m = new SortedEnumMap(Month.class);

for (Month v : Month.values()) {
    m.put(v, v.getValue());
}

System.out.println("firstKey():       " + m.firstKey());
System.out.println("lastKey():        " + m.lastKey());
System.out.println("headMap/June:     " + m.headMap(Month.JUNE));
System.out.println("tailMap/June:     " + m.tailMap(Month.JUNE));
System.out.println("subMap/April-July " + m.subMap(Month.APRIL, Month.JULY));

Я отримав:

firstKey():       JANUARY
lastKey():        DECEMBER
headMap/June:     {JANUARY=1, FEBRUARY=2, MARCH=3, APRIL=4, MAY=5}
tailMap/June:     {JUNE=6, JULY=7, AUGUST=8, SEPTEMBER=9, OCTOBER=10, NOVEMBER=11, DECEMBER=12}
subMap/April-July {APRIL=4, MAY=5, JUNE=6}

1
Ви коментуєте, що "повернута карта НЕ є" переглядом "або поточною", але ці методи (голова / під / хвіст-карта) ОБОВ'ЯЗКОВО повертають подання.
assylias

1
Я бачу, що жодна з ваших відповідей насправді не відповідає на моє основне запитання, але ваша відповідь буде, принаймні, дуже корисною для інших людей з цією проблемою, тому я дам вам кредити за ваші зусилля. Можливо, хтось із Oracle прочитає та потягне ...
rawcode

@assylias Саме так, і я чітко згадував про це у дописі
ernest_k

Сортирована карта, яка реалізує всі ті операції, призначені для використання відсортованої природи, за допомогою лінійних пошуків…
Holger

3

Відкрити запит на функцію

Мені вдалося знайти цю проблему для OpenJDK . Це з 2005 року, але все ще є відкритим / невирішеним.

Я припускаю, що немає жодної «вагомої причини» для цього не реалізуватися.


дякую вам за це. Тим часом я побачив відповідь ernest_k, яка також не відповідає на моє запитання, але створює приємне рішення проблеми, що лежить в основі мого питання. Вибачте, що не надав вам кредитів, як я згадав першим, але я думаю, що ernest_k заслуговує цього на роботу.
rawcode

@rawcode Це цілком зрозуміло. Якби я був ти, я також прийняв би відповідь ernest_k - це набагато корисніше мого.
Амонгален
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.