反復せずにハッシュマップから1つのエントリを取得する方法


172

Entry<K,V>キーが不明な場合に、反復せずにHashMapから1つだけを取得するエレガントな方法はありますか?

エントリーのエントリー順は重要ではないので、次のように言うことができますか?

hashMapObject.get(zeroth_index);

私はそのようなget by indexメソッドが存在しないことを知っていますが。

以下のアプローチを試した場合でも、ハッシュマップのすべてのエントリセットを取得する必要があります

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

提案は大歓迎です。

編集:要件を満たすのに他のデータ構造を提案してください。

回答:


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おらず、TreeMapand ConcurrentSkipListMap:(
janko

1
firstEntry()はNavigableMapインターフェースで定義されています。
パーÖstlund

ああ、ありがとう、メソッドSortedMapがあったので見ただけfirstKey()です。
janko

251

マップは順序付けされていないため、「最初のエントリ」などはありません。Mapそれが、(またはHashMap)にget-by-indexメソッドがない理由でもあります。

あなたはこれを行うことができます:

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が、キーは挿入された順序で保持されます。
Matthieu

2
はい、一般的にマップは順序付けMapされLinkedHashMapTreeMapいませんが、およびなどの一部の実装では順序が定義されています。(HashMapしない)。
Jesper

1
選択された回答よりも良い回答-選択された回答は、キーがComparable型であることを期待するTreeMapを使用するため。
Yazad

28

イテレータが最も簡単な解決策かもしれないと思います。

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

別の解決策(かなりではありません):

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

またはまだ(良くない):

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

7
2番目または3番目のバージョンを使用する理由はありません。最初の1つは完全に問題ありませんが、他の2つは配列/リストを提供しないために多くの時間を浪費しています。
Joachim Sauer、

4
私は同意します。したがって、「きれいではない」コメントです;-)
カドリアン


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);
    }
}

編集:私は意図的にこれのジェネリック側を掘り下げませんでした...


4

「繰り返しなし」とはどういう意味ですか?

使用できmap.entrySet().iterator().next()、マップを反復処理しません(「各オブジェクトに触れる」という意味で)。Entry<K, V>ただし、イテレータを使用せずにを取得することはできません。Map.EntryのJavadocは次のように述べています。

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バース-2012年

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()ですが、マップに何もない場合のデフォルト(この場合はnull)を指定することもできます。

Iterables.getLast( someMap.values(), null ); マップの最後の要素を返します。

Iterables.get( someMap.values(), 7, null ); Mapの7番目の要素が存在する場合はそれを返し、そうでない場合はデフォルト値(この場合はnull)を返します。

ただし、HashMapは順序付けされていないことIterables.getFirstを覚えておいてください。そのため、そこに投げた最初のアイテムを返すことを期待しないでくださいIterables.getLast おそらくマップされた値ます。

それだけでGuavaライブラリを追加する価値はないかもしれませんが、そのライブラリ内で他のクールなユーティリティを使用している場合は...


1

あなたの編集に続いて、これが私の提案です:

エントリが1つしかない場合は、マップをデュアルオブジェクトに置き換えることができます。タイプと好みに応じて:

  • 配列(2つの値、キーと値)
  • 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
このコードは質問に答えることがありますが、このコードが質問に答える理由や方法に関する追加のコンテキストを提供すると、長期的な価値が向上します。
Alex Riabov

1
はい、コードとともに説明を追加してください。
jkdev

-3

私は答えを得ました:(それは簡単です)

ArrayListを受け取ってキャストし、arraylistのサイズを見つけます。ここにあります :

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

サイズが表示されます。(提案を与える)。それは働いています。


2
これはどのようにしてハッシュマップから任意のアイテムを1つ取得しますか?
大佐32
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.