Встановлюється нечутливий рядок як ключ HashMap


178

Я хотів би використовувати рядок, нечутливий до регістру, як ключ HashMap з наступних причин.

  • Під час ініціалізації моя програма створює HashMap з визначеною користувачем String
  • Під час обробки події (мережевий трафік у моєму випадку) я міг би отримати String в іншому випадку, але я мав би змогу знайти <key, value>HashMap з ігнорування випадку, отриманого від трафіку.

Я дотримувався такого підходу

CaseInsensitiveString.java

    public final class CaseInsensitiveString {
            private String s;

            public CaseInsensitiveString(String s) {
                            if (s == null)
                            throw new NullPointerException();
                            this.s = s;
            }

            public boolean equals(Object o) {
                            return o instanceof CaseInsensitiveString &&
                            ((CaseInsensitiveString)o).s.equalsIgnoreCase(s);
            }

            private volatile int hashCode = 0;

            public int hashCode() {
                            if (hashCode == 0)
                            hashCode = s.toUpperCase().hashCode();

                            return hashCode;
            }

            public String toString() {
                            return s;
            }
    }

LookupCode.java

    node = nodeMap.get(new CaseInsensitiveString(stringFromEvent.toString()));

Через це я створюю новий об'єкт CaseInsensitiveString для кожної події. Отже, це може вразити продуктивність.

Чи є інший спосіб вирішити це питання?


3
[Чи є хороший спосіб мати карту <String,?> Дістати і поставити ігнорування випадку?] [1] [1]: stackoverflow.com/questions/212562/…
Beau Grantham

Я коментував наведені нижче проблеми, але вони знаходяться нижче порогу, тому люди можуть їх не бачити. Остерігайтеся підкласифікації HashMap. JDK8 змінив реалізацію, і тепер вам потрібно змінити команду putAll (принаймні) для того, щоб ці пропозиції працювали.
Стів N

Це має добре працювати. Ви можете скористатися полегшеною вагою, щоб позбутися нової інстанції об'єкта.
topkara

Відповіді:


331
Map<String, String> nodeMap = 
    new TreeMap<>(String.CASE_INSENSITIVE_ORDER);

Це дійсно все, що вам потрібно.


6
Це найпростіше на сьогоднішній день, а також зберігає випадок клавіш при повторенні через них.
Ральф

Це прекрасно! Це був завершальний фрагмент головоломки для створення впорядкованої структури в ColdFusion, яка зберігає можливість використовувати крапкові позначення. Замість var stru = {} або var stru = structnew () ви можете використовувати var stru = createObject ('java', 'java.util.TreeMap'). Init (createObject ('java', 'java.lang.String') ) .CASE_INSENSITIVE_ORDER); ПОВНО, але це працює;)
Ерік Фуллер

public static <K extends String, V> Map<K, V> caseInsensitiveMap() { return new TreeMap<K, V>(String.CASE_INSENSITIVE_ORDER); }
pllee

5
Немає необхідності, <K extends String>оскільки Stringє остаточним: public static <V> Map<String, V> caseInsensitiveMap() { return new TreeMap<String, V>(String.CASE_INSENSITIVE_ORDER); }
Roel Spilker

19
Майте на увазі, що TreeMap не є постійним часом для основних операцій. Це не проблема для більшості програм, але варто пам’ятати. Від JavaDoc: "Ця реалізація забезпечує гарантовану вартість журналу (n) часу для операцій, які містять, кладуть, ставлять і видаляють. Алгоритми - це адаптації тих, що вводяться в алгоритми Кормена, Лейзерсона та Рівеста".
Джеймс Шек

57

Як запропонував Гідо Гарсія у своїй відповіді тут :

import java.util.HashMap;

public class CaseInsensitiveMap extends HashMap<String, String> {

    @Override
    public String put(String key, String value) {
       return super.put(key.toLowerCase(), value);
    }

    // not @Override because that would require the key parameter to be of type Object
    public String get(String key) {
       return super.get(key.toLowerCase());
    }
}

Або

https://commons.apache.org/proper/commons-collections/apidocs/org/apache/commons/collections4/map/CaseInsensitiveMap.html


28
Як щодо вмісту, putAll тощо?
assylias

14
Це не працює в деяких мовах, як турецька. Google "Тест на індичку"
Уго

5
@assylias: правда, containsKey()і її remove()слід перекрити так само, як і get(). то HashMap.putAll()використовувані для впровадження put(), так що не повинно бути проблемою - до тих пір , як підлокітників реалізації Hashmap те ж саме. ;) також get()підпис методу бере Objectяк аргумент, а не a String. код також не перевіряє наявність нульового ключа:super.get(key == null ? null : key.toString().toLowercase());
sfera

зауважте, що якщо вам потрібен конструктор копіювання HashMap(<? extends String, ? extends String> anotherMap), ви не повинні викликати суперреалізацію того самого конструктора, оскільки ця операція не гарантує, що ваші ключі мають малі регістри. ви можете використовувати: super(anotherMap.size()); putAll(anotherMap);натомість.
sfera

Що робити, якщо ви хочете, щоб значення карти не були рядками? (тобто CaseInsensitiveMap<String, Integer>)
Адам Паркін

16

Один із підходів полягає у створенні користувацького підкласу класу Apache Commons AbstractHashedMap, що переосмислює і hashтаisEqualKeys методи способи виконувати хеш-чутливість до регістру та порівняння ключів. (Примітка - я ніколи цього не пробував сам ...)

Це дозволяє уникнути накладних витрат на створення нових об'єктів щоразу, коли потрібно робити пошук або оновлення карти. І загальні Mapоперації повинні O (1) ... так само, як звичайніHashMap .

І якщо ви готові прийняти вибір реалізації, який вони зробили, Apache Commons CaseInsensitiveMapвиконує роботу з налаштування / спеціалізації AbstractHashedMapдля вас.


Але якщо O (logN) getта putоперації є прийнятними, порівняння TreeMapз рядком, нечутливим до регістру, є варіантом; наприклад використанняString.CASE_INSENSITIVE_ORDER .

І якщо ви не проти створити новий тимчасовий об'єкт String кожного разу, коли ви зробите це putчи get, то відповідь Vishal просто чудова. (Хоча зауважу, що ви б не зберігали початковий корпус ключів, якби це зробили ...)


6

Підклас HashMapі створити версію, яка запускає малі літери ключа на putіget (і , можливо , інших ключових-орієнтованих методів).

Або складіть a HashMapв новий клас і делегуйте все на карті, але перекладіть ключі.

Якщо вам потрібно зберегти оригінальний ключ, ви можете або підтримувати подвійні карти, або зберігати оригінальний ключ разом зі значенням.


Ви маєте на увазі робити String.toLowerCase () під час пошуку?
rs

@ user710178 Не тільки під час пошуку, але й під час зберігання.
Дейв Ньютон

@ user710178 О, так, як вказує інша відповідь, це вже існує, якщо ви не заперечуєте проти додаткової залежності.
Дейв Ньютон

@StephenC Якщо він відповідає вашим потребам, обов'язково; ОП вказав a HashMap, так що це я пішов :) О, ти маєш на увазі Commons; Я бачу. Я здогадуюсь, доки вам це не потрібно узагальнено (чи вони, нарешті, мають дженерики зараз?)
Дейв Ньютон

1
Для JDK 8 і вище вам також потрібно буде (принаймні) переосмислити putAll, оскільки реалізація змінилася.
Стів N

4

На думку мені спадають два варіанти:

  1. Ви можете використовувати безпосередньо s.toUpperCase().hashCode();ключ як ключMap .
  2. Ви можете використовувати TreeMap<String>спеціальний засіб, Comparatorякий ігнорує випадок.

В іншому випадку, якщо ви віддаєте перевагу своєму рішенню, замість того, щоб визначати новий вид String, я б скоріше реалізував нову карту з необхідною функцією нечутливості випадку.


3

Чи не було б краще "обернути" String для запам'ятовування hashCode. У звичайному класі String hashCode () вперше є O (N), а потім це O (1), оскільки він зберігається для подальшого використання.

public class HashWrap {
    private final String value;
    private final int hash;

    public String get() {
        return value;
    }

    public HashWrap(String value) {
        this.value = value;
        String lc = value.toLowerCase();
        this.hash = lc.hashCode();
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o instanceof HashWrap) {
            HashWrap that = (HashWrap) o;
            return value.equalsIgnoreCase(that.value);
        } else {
            return false;
        }
    }

    @Override
    public int hashCode() {
        return this.hash;
    }

    //might want to implement compare too if you want to use with SortedMaps/Sets.
}

Це дозволить вам використовувати будь-яку реалізацію Hashtable в java та мати O (1) hasCode ().



2

На основі інших відповідей в основному є два підходи: підкласифікація HashMapабо завершення String. Перший вимагає трохи більше роботи. Насправді, якщо ви хочете зробити це правильно, ви повинні перекрити майже всі методи (containsKey, entrySet, get, put, putAll and remove ).

У будь-якому випадку це проблема. Якщо ви хочете уникнути майбутніх проблем, вам потрібно вказати операцію Localeна Stringвипадок, якщо ви хочете . Так ви створили б нові методи ( get(String, Locale), ...). Все простіше і чіткіше обгортання Рядок:

public final class CaseInsensitiveString {

    private final String s;

    public CaseInsensitiveString(String s, Locale locale) {
        this.s = s.toUpperCase(locale);
    }

    // equals, hashCode & toString, no need for memoizing hashCode
}

І добре, що стосується ваших турбот щодо продуктивності: передчасна оптимізація - корінь усього зла :)


2
"І добре, що стосується ваших занепокоєнь щодо продуктивності: передчасна оптимізація - корінь усього зла :)" - Навпаки, використання цього в якості приводу завжди писати неефективний код - це те, що є злом.
Гордон

1
Насправді @Gordon, обидва однаково погані, залежно від контексту. Мітка "зло" є ознакою чорно-білого мислення, як "найкраща практика" та різних інших недобрих фраз, якими схильні користуватися багато ІТ-людей. Краще уникати цього цілком.
Стівен C

Я виявив, що розповідати людям, що вони не дотримуються "найкращої практики", як правило, створюють менше копання підборів, ніж говорити їм, що вони мають погані практики.
Гордон

0

Це адаптер для HashMaps, який я реалізував для недавнього проекту. Працює певним чином до того, що робить @SandyR, але інкапсулює логіку перетворення, щоб ви не вручну конвертували рядки в об’єкт обгортки.

Я використовував функції Java 8, але, маючи кілька змін, ви можете адаптувати її до попередніх версій. Я перевірив його на найбільш поширені сценарії, крім нових функцій потоку Java 8.

В основному він обертає HashMap, спрямовує на нього всі функції, перетворюючи рядки в / з об'єкта обгортки. Але мені довелося також адаптувати KeySet і EntrySet, оскільки вони пересилають деякі функції до самої карти. Тому я повертаю два нові набори для ключів та записів, які фактично обертають оригінальний keySet () та entrySet ().

Одне зауваження: Java 8 змінила реалізацію методу putAll, який я не міг знайти простий спосіб перемогти. Тому поточна реалізація може погіршити продуктивність, особливо якщо ви використовуєте putAll () для великого набору даних.

Будь ласка, повідомте мене, якщо ви знайшли помилку чи маєте пропозиції щодо вдосконалення коду.

пакет webbit.collections;

import java.util.*;
import java.util.function.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;


public class CaseInsensitiveMapAdapter<T> implements Map<String,T>
{
    private Map<CaseInsensitiveMapKey,T> map;
    private KeySet keySet;
    private EntrySet entrySet;


    public CaseInsensitiveMapAdapter()
    {
    }

    public CaseInsensitiveMapAdapter(Map<String, T> map)
    {
        this.map = getMapImplementation();
        this.putAll(map);
    }

    @Override
    public int size()
    {
        return getMap().size();
    }

    @Override
    public boolean isEmpty()
    {
        return getMap().isEmpty();
    }

    @Override
    public boolean containsKey(Object key)
    {
        return getMap().containsKey(lookupKey(key));
    }

    @Override
    public boolean containsValue(Object value)
    {
        return getMap().containsValue(value);
    }

    @Override
    public T get(Object key)
    {
        return getMap().get(lookupKey(key));
    }

    @Override
    public T put(String key, T value)
    {
        return getMap().put(lookupKey(key), value);
    }

    @Override
    public T remove(Object key)
    {
        return getMap().remove(lookupKey(key));
    }

    /***
     * I completely ignore Java 8 implementation and put one by one.This will be slower.
     */
    @Override
    public void putAll(Map<? extends String, ? extends T> m)
    {
        for (String key : m.keySet()) {
            getMap().put(lookupKey(key),m.get(key));
        }
    }

    @Override
    public void clear()
    {
        getMap().clear();
    }

    @Override
    public Set<String> keySet()
    {
        if (keySet == null)
            keySet = new KeySet(getMap().keySet());
        return keySet;
    }

    @Override
    public Collection<T> values()
    {
        return getMap().values();
    }

    @Override
    public Set<Entry<String, T>> entrySet()
    {
        if (entrySet == null)
            entrySet = new EntrySet(getMap().entrySet());
        return entrySet;
    }

    @Override
    public boolean equals(Object o)
    {
        return getMap().equals(o);
    }

    @Override
    public int hashCode()
    {
        return getMap().hashCode();
    }

    @Override
    public T getOrDefault(Object key, T defaultValue)
    {
        return getMap().getOrDefault(lookupKey(key), defaultValue);
    }

    @Override
    public void forEach(final BiConsumer<? super String, ? super T> action)
    {
        getMap().forEach(new BiConsumer<CaseInsensitiveMapKey, T>()
        {
            @Override
            public void accept(CaseInsensitiveMapKey lookupKey, T t)
            {
                action.accept(lookupKey.key,t);
            }
        });
    }

    @Override
    public void replaceAll(final BiFunction<? super String, ? super T, ? extends T> function)
    {
        getMap().replaceAll(new BiFunction<CaseInsensitiveMapKey, T, T>()
        {
            @Override
            public T apply(CaseInsensitiveMapKey lookupKey, T t)
            {
                return function.apply(lookupKey.key,t);
            }
        });
    }

    @Override
    public T putIfAbsent(String key, T value)
    {
        return getMap().putIfAbsent(lookupKey(key), value);
    }

    @Override
    public boolean remove(Object key, Object value)
    {
        return getMap().remove(lookupKey(key), value);
    }

    @Override
    public boolean replace(String key, T oldValue, T newValue)
    {
        return getMap().replace(lookupKey(key), oldValue, newValue);
    }

    @Override
    public T replace(String key, T value)
    {
        return getMap().replace(lookupKey(key), value);
    }

    @Override
    public T computeIfAbsent(String key, final Function<? super String, ? extends T> mappingFunction)
    {
        return getMap().computeIfAbsent(lookupKey(key), new Function<CaseInsensitiveMapKey, T>()
        {
            @Override
            public T apply(CaseInsensitiveMapKey lookupKey)
            {
                return mappingFunction.apply(lookupKey.key);
            }
        });
    }

    @Override
    public T computeIfPresent(String key, final BiFunction<? super String, ? super T, ? extends T> remappingFunction)
    {
        return getMap().computeIfPresent(lookupKey(key), new BiFunction<CaseInsensitiveMapKey, T, T>()
        {
            @Override
            public T apply(CaseInsensitiveMapKey lookupKey, T t)
            {
                return remappingFunction.apply(lookupKey.key, t);
            }
        });
    }

    @Override
    public T compute(String key, final BiFunction<? super String, ? super T, ? extends T> remappingFunction)
    {
        return getMap().compute(lookupKey(key), new BiFunction<CaseInsensitiveMapKey, T, T>()
        {
            @Override
            public T apply(CaseInsensitiveMapKey lookupKey, T t)
            {
                return remappingFunction.apply(lookupKey.key,t);
            }
        });
    }

    @Override
    public T merge(String key, T value, BiFunction<? super T, ? super T, ? extends T> remappingFunction)
    {
        return getMap().merge(lookupKey(key), value, remappingFunction);
    }

    protected  Map<CaseInsensitiveMapKey,T> getMapImplementation() {
        return new HashMap<>();
    }

    private Map<CaseInsensitiveMapKey,T> getMap() {
        if (map == null)
            map = getMapImplementation();
        return map;
    }

    private CaseInsensitiveMapKey lookupKey(Object key)
    {
        return new CaseInsensitiveMapKey((String)key);
    }

    public class CaseInsensitiveMapKey {
        private String key;
        private String lookupKey;

        public CaseInsensitiveMapKey(String key)
        {
            this.key = key;
            this.lookupKey = key.toUpperCase();
        }

        @Override
        public boolean equals(Object o)
        {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;

            CaseInsensitiveMapKey that = (CaseInsensitiveMapKey) o;

            return lookupKey.equals(that.lookupKey);

        }

        @Override
        public int hashCode()
        {
            return lookupKey.hashCode();
        }
    }

    private class KeySet implements Set<String> {

        private Set<CaseInsensitiveMapKey> wrapped;

        public KeySet(Set<CaseInsensitiveMapKey> wrapped)
        {
            this.wrapped = wrapped;
        }


        private List<String> keyList() {
            return stream().collect(Collectors.toList());
        }

        private Collection<CaseInsensitiveMapKey> mapCollection(Collection<?> c) {
            return c.stream().map(it -> lookupKey(it)).collect(Collectors.toList());
        }

        @Override
        public int size()
        {
            return wrapped.size();
        }

        @Override
        public boolean isEmpty()
        {
            return wrapped.isEmpty();
        }

        @Override
        public boolean contains(Object o)
        {
            return wrapped.contains(lookupKey(o));
        }

        @Override
        public Iterator<String> iterator()
        {
            return keyList().iterator();
        }

        @Override
        public Object[] toArray()
        {
            return keyList().toArray();
        }

        @Override
        public <T> T[] toArray(T[] a)
        {
            return keyList().toArray(a);
        }

        @Override
        public boolean add(String s)
        {
            return wrapped.add(lookupKey(s));
        }

        @Override
        public boolean remove(Object o)
        {
            return wrapped.remove(lookupKey(o));
        }

        @Override
        public boolean containsAll(Collection<?> c)
        {
            return keyList().containsAll(c);
        }

        @Override
        public boolean addAll(Collection<? extends String> c)
        {
            return wrapped.addAll(mapCollection(c));
        }

        @Override
        public boolean retainAll(Collection<?> c)
        {
            return wrapped.retainAll(mapCollection(c));
        }

        @Override
        public boolean removeAll(Collection<?> c)
        {
            return wrapped.removeAll(mapCollection(c));
        }

        @Override
        public void clear()
        {
            wrapped.clear();
        }

        @Override
        public boolean equals(Object o)
        {
            return wrapped.equals(lookupKey(o));
        }

        @Override
        public int hashCode()
        {
            return wrapped.hashCode();
        }

        @Override
        public Spliterator<String> spliterator()
        {
            return keyList().spliterator();
        }

        @Override
        public boolean removeIf(Predicate<? super String> filter)
        {
            return wrapped.removeIf(new Predicate<CaseInsensitiveMapKey>()
            {
                @Override
                public boolean test(CaseInsensitiveMapKey lookupKey)
                {
                    return filter.test(lookupKey.key);
                }
            });
        }

        @Override
        public Stream<String> stream()
        {
            return wrapped.stream().map(it -> it.key);
        }

        @Override
        public Stream<String> parallelStream()
        {
            return wrapped.stream().map(it -> it.key).parallel();
        }

        @Override
        public void forEach(Consumer<? super String> action)
        {
            wrapped.forEach(new Consumer<CaseInsensitiveMapKey>()
            {
                @Override
                public void accept(CaseInsensitiveMapKey lookupKey)
                {
                    action.accept(lookupKey.key);
                }
            });
        }
    }

    private class EntrySet implements Set<Map.Entry<String,T>> {

        private Set<Entry<CaseInsensitiveMapKey,T>> wrapped;

        public EntrySet(Set<Entry<CaseInsensitiveMapKey,T>> wrapped)
        {
            this.wrapped = wrapped;
        }


        private List<Map.Entry<String,T>> keyList() {
            return stream().collect(Collectors.toList());
        }

        private Collection<Entry<CaseInsensitiveMapKey,T>> mapCollection(Collection<?> c) {
            return c.stream().map(it -> new CaseInsensitiveEntryAdapter((Entry<String,T>)it)).collect(Collectors.toList());
        }

        @Override
        public int size()
        {
            return wrapped.size();
        }

        @Override
        public boolean isEmpty()
        {
            return wrapped.isEmpty();
        }

        @Override
        public boolean contains(Object o)
        {
            return wrapped.contains(lookupKey(o));
        }

        @Override
        public Iterator<Map.Entry<String,T>> iterator()
        {
            return keyList().iterator();
        }

        @Override
        public Object[] toArray()
        {
            return keyList().toArray();
        }

        @Override
        public <T> T[] toArray(T[] a)
        {
            return keyList().toArray(a);
        }

        @Override
        public boolean add(Entry<String,T> s)
        {
            return wrapped.add(null );
        }

        @Override
        public boolean remove(Object o)
        {
            return wrapped.remove(lookupKey(o));
        }

        @Override
        public boolean containsAll(Collection<?> c)
        {
            return keyList().containsAll(c);
        }

        @Override
        public boolean addAll(Collection<? extends Entry<String,T>> c)
        {
            return wrapped.addAll(mapCollection(c));
        }

        @Override
        public boolean retainAll(Collection<?> c)
        {
            return wrapped.retainAll(mapCollection(c));
        }

        @Override
        public boolean removeAll(Collection<?> c)
        {
            return wrapped.removeAll(mapCollection(c));
        }

        @Override
        public void clear()
        {
            wrapped.clear();
        }

        @Override
        public boolean equals(Object o)
        {
            return wrapped.equals(lookupKey(o));
        }

        @Override
        public int hashCode()
        {
            return wrapped.hashCode();
        }

        @Override
        public Spliterator<Entry<String,T>> spliterator()
        {
            return keyList().spliterator();
        }

        @Override
        public boolean removeIf(Predicate<? super Entry<String, T>> filter)
        {
            return wrapped.removeIf(new Predicate<Entry<CaseInsensitiveMapKey, T>>()
            {
                @Override
                public boolean test(Entry<CaseInsensitiveMapKey, T> entry)
                {
                    return filter.test(new FromCaseInsensitiveEntryAdapter(entry));
                }
            });
        }

        @Override
        public Stream<Entry<String,T>> stream()
        {
            return wrapped.stream().map(it -> new Entry<String, T>()
            {
                @Override
                public String getKey()
                {
                    return it.getKey().key;
                }

                @Override
                public T getValue()
                {
                    return it.getValue();
                }

                @Override
                public T setValue(T value)
                {
                    return it.setValue(value);
                }
            });
        }

        @Override
        public Stream<Map.Entry<String,T>> parallelStream()
        {
            return StreamSupport.stream(spliterator(), true);
        }

        @Override
        public void forEach(Consumer<? super Entry<String, T>> action)
        {
            wrapped.forEach(new Consumer<Entry<CaseInsensitiveMapKey, T>>()
            {
                @Override
                public void accept(Entry<CaseInsensitiveMapKey, T> entry)
                {
                    action.accept(new FromCaseInsensitiveEntryAdapter(entry));
                }
            });
        }
    }

    private class EntryAdapter implements Map.Entry<String,T> {
        private Entry<String,T> wrapped;

        public EntryAdapter(Entry<String, T> wrapped)
        {
            this.wrapped = wrapped;
        }

        @Override
        public String getKey()
        {
            return wrapped.getKey();
        }

        @Override
        public T getValue()
        {
            return wrapped.getValue();
        }

        @Override
        public T setValue(T value)
        {
            return wrapped.setValue(value);
        }

        @Override
        public boolean equals(Object o)
        {
            return wrapped.equals(o);
        }

        @Override
        public int hashCode()
        {
            return wrapped.hashCode();
        }


    }

    private class CaseInsensitiveEntryAdapter implements Map.Entry<CaseInsensitiveMapKey,T> {

        private Entry<String,T> wrapped;

        public CaseInsensitiveEntryAdapter(Entry<String, T> wrapped)
        {
            this.wrapped = wrapped;
        }

        @Override
        public CaseInsensitiveMapKey getKey()
        {
            return lookupKey(wrapped.getKey());
        }

        @Override
        public T getValue()
        {
            return wrapped.getValue();
        }

        @Override
        public T setValue(T value)
        {
            return wrapped.setValue(value);
        }
    }

    private class FromCaseInsensitiveEntryAdapter implements Map.Entry<String,T> {

        private Entry<CaseInsensitiveMapKey,T> wrapped;

        public FromCaseInsensitiveEntryAdapter(Entry<CaseInsensitiveMapKey, T> wrapped)
        {
            this.wrapped = wrapped;
        }

        @Override
        public String getKey()
        {
            return wrapped.getKey().key;
        }

        @Override
        public T getValue()
        {
            return wrapped.getValue();
        }

        @Override
        public T setValue(T value)
        {
            return wrapped.setValue(value);
        }
    }


}

0

Через це я створюю новий об'єкт CaseInsensitiveString для кожної події. Отже, це може вразити продуктивність.

Створення обгортки або перетворення ключа в малі регістри перед пошуком обох створюють нові об’єкти. Написання власної реалізації java.util.Map - єдиний спосіб уникнути цього. Це не надто важко, і ІМО того вартий. Я знайшов наступну хеш-функцію, яка працює досить добре, до кількох сотень клавіш.

static int ciHashCode(String string)
{
    // length and the low 5 bits of hashCode() are case insensitive
    return (string.hashCode() & 0x1f)*33 + string.length();
}

-3

Як щодо використання потоків java 8.

nodeMap.entrySet().stream().filter(x->x.getKey().equalsIgnoreCase(stringfromEven.toString()).collect(Collectors.toList())

Це не дає змоги шукати значення на карті в регістровому режимі.
Гілі

equalsignorecase зробив би це не так?
Амарендра Редді

Ви будуєте список. ОП попросили карту.
Гілі

Це знищує вигідність складнощі O (1) карти.
Пол Руні
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.