як отримати один запис із хешмапу без ітерації


172

Чи є елегантний спосіб отримати лише один Entry<K,V>з HashMap, без ітерації, якщо ключ не відомий.

Оскільки порядок вступу не є важливим, чи можна сказати щось подібне

hashMapObject.get(zeroth_index);

Хоча я знаю, що не існує такого отримання методом індексів.

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

for(Map.Entry<String, String> entry : MapObj.entrySet()) {
    return entry;
}

Пропозиції вітаються.

EDIT: Будь ласка, запропонуйте будь-яку іншу Структуру даних достатньою вимогою.

Відповіді:


93

Відповідь Джеспера хороша. Іншим рішенням є використання TreeMap (ви просили інших структур даних).

TreeMap<String, String> myMap = new TreeMap<String, String>();
String first = myMap.firstEntry().getValue();
String firstOther = myMap.get(myMap.firstKey());

TreeMap має накладні витрати, тому HashMap швидше, але просто як приклад альтернативного рішення.


Або ConcurrentSkipListMap
Стівен Денне

Чомусь firstEntry()метод не визначений в інтерфейсі, SortedMapа лише у TreeMapта ConcurrentSkipListMap:(
janko

1
firstEntry () визначається в інтерфейсі NavigableMap.
Пер Естлунд

Ах, дякую, я дивився лише SortedMapтому, що у нього був firstKey()метод.
janko

251

Карти не впорядковані, тому не існує такого поняття, як "перший запис", і тому також немає методу "get-by-index" Map(або HashMap).

Ви можете це зробити:

Map<String, String> map = ...;  // wherever you get this from

// Get the first entry that the iterator returns
Map.Entry<String, String> entry = map.entrySet().iterator().next();

(Примітка. Перевірка порожньої карти пропущена).

Ваш код не отримує всіх записів на карті, він негайно повертається (і виривається з циклу) з першим знайденим записом.

Щоб надрукувати ключ і значення цього першого елемента:

System.out.println("Key: "+entry.getKey()+", Value: "+entry.getValue());

Примітка: Виклик iterator()не означає, що ви повторюєтесь по всій карті.


3
Просто бічна примітка: LinkedHashMapзберігає ключі в тому порядку, в який вони були вставлені.
Матьє

2
Так, карти взагалі не впорядковані, але деякі Mapреалізації, такі як LinkedHashMapі TreeMapмають певний порядок. ( HashMapні).
Джеспер

1
Краща відповідь, ніж обрана відповідь - оскільки обрана відповідь використовує TreeMap, який очікує, що ключ буде типом Порівнянним.
Язад

28

Я думаю, що ітератор може бути найпростішим рішенням.

return hashMapObject.entrySet().iterator().next();

Ще одне рішення (не дуже):

return new ArrayList(hashMapObject.entrySet()).get(0);

Або ще (не краще):

return hashMapObject.entrySet().toArray()[0];

7
Немає підстав використовувати другу чи третю версію. Перший ідеально чужий, два інших витрачають багато часу, надаючи масив / Список ні за що.
Йоахім Зауер

4
Я згоден, отже, "не дуже" коментарі ;-)
cadrian

14

Отримати значення, перетворити його в масив, отримати перший елемент масиву:

map.values().toArray()[0]

W.


8

Чому ви хочете уникати entrySet()його виклику, як правило, не створюється абсолютно новий об'єкт із власним контекстом, а натомість просто надає об'єкт фасаду. Простіше кажучи entrySet(), це досить дешева операція.


8

Якщо ви використовуєте Java 8, це так само просто, як findFirst () :

Короткий приклад:

Optional<Car> theCarFoundOpt = carMap.values().stream().findFirst();

if(theCarFoundOpt.isPresent()) {
    return theCarFoundOpt.get().startEngine();
}

6

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

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@SuppressWarnings("unchecked")
public class IndexedMap extends HashMap {

    private List<Object> keyIndex;

    public IndexedMap() {
        keyIndex = new ArrayList<Object>();
    }

    /**
     * Returns the key at the specified position in this Map's keyIndex.
     * 
     * @param index
     *            index of the element to return
     * @return the element at the specified position in this list
     * @throws IndexOutOfBoundsException
     *             if the index is out of range (index < 0 || index >= size())
     */
    public Object get(int index) {
        return keyIndex.get(index);
    }

    @Override
    public Object put(Object key, Object value) {

        addKeyToIndex(key);
        return super.put(key, value);
    }

    @Override
    public void putAll(Map source) {

        for (Object key : source.keySet()) {
            addKeyToIndex(key);
        }
        super.putAll(source);
    }

    private void addKeyToIndex(Object key) {

        if (!keyIndex.contains(key)) {
            keyIndex.add(key);
        }
    }

    @Override
    public Object remove(Object key) {

        keyIndex.remove(key);
        return super.remove(key);
    }
}

EDIT: Я навмисно не заглиблювався в загальну сторону цього ...


4

Що ви маєте на увазі під "без повторення"?

Ви можете використовувати map.entrySet().iterator().next()та не повторювати карту (у значенні "торкання кожного об'єкта"). Ви не зможете захопити Entry<K, V>без використання ітератора. Javadoc Map.Entry говорить:

Метод Map.entrySet повертає збірний вигляд карти, елементи якої належать до цього класу. Єдиний спосіб отримати посилання на запис на карті - це ітератор цього виду колекції. Ці об’єкти Map.Entry дійсні лише протягом тривалості ітерації.

Чи можете ви пояснити більш детально, що ви намагаєтеся досягти? Якщо ви хочете спочатку обробити об'єкти, які відповідають певному критерію (наприклад, "мати певний ключ") і повернутися до інших об'єктів в іншому випадку, тоді подивіться на PriorityQueue . Він буде упорядковувати ваші об’єкти на основі природного замовлення або визначеного на замовлення, Comparatorякий ви надаєте.


4
import java.util.*;

public class Friday {
    public static void main(String[] args) {
        Map<String, Integer> map = new HashMap<String, Integer>();

        map.put("code", 10);
        map.put("to", 11);
        map.put("joy", 12);

        if (! map.isEmpty()) {
            Map.Entry<String, Integer> entry = map.entrySet().iterator().next();
            System.out.println(entry);
        }
    }
}

Цей підхід не працює, оскільки ви використовували HashMap. Я припускаю, що використання LinkedHashMap буде правильним рішенням у цьому випадку.


1
Який метод існує в LinkedHashMap, що змушує LinkedHashmap працювати, що цей код не працює?
SL Barth - Відновіть Моніку

3

Це дозволить отримати єдиний запис з карти, який приблизно наближається до даного "перший" насправді не застосовується.

import java.util.*;

public class Friday {
    public static void main(String[] args) {
        Map<String, Integer> map = new HashMap<String, Integer>();

        map.put("code", 10);
        map.put("to", 11);
        map.put("joy", 12);

        if (! map.isEmpty()) {
            Map.Entry<String, Integer> entry = map.entrySet().iterator().next();
            System.out.println(entry);
        }
    }
}

2

Тут натрапили на пошуки того ж самого ... Я тоді згадав Iterablesклас з бібліотеки Гуави .

Для того, щоб отримати «перший» елемент: Iterables.getFirst( someMap.values(), null );.
По суті робить те ж саме Map.values().iterator().next(), але також дозволяє вказати типовий за умовчанням (у цьому випадку нульовий), якщо на карті нічого не буде.

Iterables.getLast( someMap.values(), null ); повертає останній елемент на карті.

Iterables.get( someMap.values(), 7, null ); повертає 7-й елемент на карті, якщо він існує, інакше значення за замовчуванням (у цьому випадку є нульовим).

Пам'ятайте, що HashMaps не впорядковані ... тому не сподівайтесь Iterables.getFirstповернути перший предмет, який ви кинули туди ... також Iterables.getLast. Може бути корисно , щоб отримати більш відображене значення , хоча.

Можливо, не варто додавати бібліотеку Guava саме для цього, але якщо вам трапляється використовувати деякі інші цікаві утиліти в цій бібліотеці ...


1

Після вашого редагування, ось моя пропозиція:

Якщо у вас є лише один запис, ви можете замінити карту подвійним об'єктом. Залежно від типів та ваших уподобань:

  • масив (з 2 значень, ключа та значення)
  • простий об’єкт з двома властивостями

0
map<string,string>m;
auto it=m.begin();//get iterator to the first element of map(m)
return m->first;//return first string(1st string in map<string,string>m)
//Incase you want the second string 
//you can use return m->second(2st string in map<string,string>m)
//if you want to iterate the whole map you can use loop
for(auto it:m)//m is a map
   cout<<it->first<<endl;

4
Хоча цей код може відповісти на питання, надаючи додатковий контекст стосовно того, чому та / або як цей код відповідає на питання, покращує його довгострокове значення.
Олексій Рябов

1
Так, будь ласка, додайте пояснення разом із кодом.
jkdev

-3

Я отримав відповідь: (Це просто)

Візьміть ArrayList, потім відкиньте його і знайдіть розмір масиву. Ось :

    ArrayList count = new ArrayList();
    count=(ArrayList) maptabcolname.get("k1"); //here "k1" is Key
    System.out.println("number of elements="+count.size());

Він покаже розмір. (Дайте пропозицію). Це працює.


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