私が使用しているLinkedHashMap
、それはキーがマップに入力された順序が重要であるため。
しかし、今私は最初の場所(最初に入力されたエントリ)または最後のキーの値を取得したいと思います。
以下のような方法があるはずですfirst()
し、last()
そのようか何かを?
最初のキーエントリを取得するだけのイテレータが必要ですか?それが私が使用した理由LinkedHashMap
です!
ありがとう!
私が使用しているLinkedHashMap
、それはキーがマップに入力された順序が重要であるため。
しかし、今私は最初の場所(最初に入力されたエントリ)または最後のキーの値を取得したいと思います。
以下のような方法があるはずですfirst()
し、last()
そのようか何かを?
最初のキーエントリを取得するだけのイテレータが必要ですか?それが私が使用した理由LinkedHashMap
です!
ありがとう!
回答:
のセマンティクスは、のセマンティクスでLinkedHashMap
はなく、マップのセマンティクスですLinkedList
。はい、挿入順序は保持されますが、それはインターフェースの側面ではなく、実装の詳細です。
「最初の」エントリを取得する最も速い方法はまだentrySet().iterator().next()
です。「最後の」エントリを取得することは可能.next()
ですが、最後に到達するまで呼び出すことにより、エントリセット全体を反復する必要があります。 while (iterator.hasNext()) { lastElement = iterator.next() }
編集:ただし、JavaSE APIを超えて進んでいく場合、Apache Commons Collectionsには独自のLinkedMap
実装があり、firstKey
やなどのメソッドがありlastKey
、探していることを実行します。インターフェースはかなりリッチです。
mylinkedmap.entrySet().iterator().next()
時間の複雑さは何ですか?O(1)ですか?
(最後のエントリを取得するために)次のようなことを試すことができますか?
linkedHashMap.entrySet().toArray()[linkedHashMap.size() -1];
T last = null ; for( T item : linkedHashMap.values() ) last = item;
またはそのようなもの。時間はO(N)ですが、メモリはO(1)です。
私は遅すぎたことを知っていますが、並外れたものではなく、ここで言及されていないいくつかのケースをいくつか提供したいと思います。誰かが効率をあまり気にしないが、もっと単純なものを望んでいる場合(おそらく、1行のコードで最後のエントリの値を見つける)、Java 8の登場により、すべてが非常に単純化され ます。いくつかの役立つシナリオを提供します。
完全を期すために、これらの代替案を、他のユーザーがこの投稿ですでに述べた配列のソリューションと比較します。すべてのケースをまとめると、特に新しい開発者にとって、(パフォーマンスが重要であるかどうかにかかわらず)役立つと思います。常に各問題の問題に依存しています
次の比較を行うために、前の回答からそれを採用しました。このソリューションは@feresrに属しています。
public static String FindLasstEntryWithArrayMethod() {
return String.valueOf(linkedmap.entrySet().toArray()[linkedmap.size() - 1]);
}
パフォーマンスが少し異なる最初のソリューションと同様
public static String FindLasstEntryWithArrayListMethod() {
List<Entry<Integer, String>> entryList = new ArrayList<Map.Entry<Integer, String>>(linkedmap.entrySet());
return entryList.get(entryList.size() - 1).getValue();
}
このメソッドは、ストリームの最後の要素を取得するまで要素のセットを減らします。さらに、確定的な結果のみを返します
public static String FindLasstEntryWithReduceMethod() {
return linkedmap.entrySet().stream().reduce((first, second) -> second).orElse(null).getValue();
}
このメソッドは、その前のすべての要素をスキップするだけで、ストリームの最後の要素を取得します
public static String FindLasstEntryWithSkipFunctionMethod() {
final long count = linkedmap.entrySet().stream().count();
return linkedmap.entrySet().stream().skip(count - 1).findFirst().get().getValue();
}
Google GuavaのIterables.getLast。リストとソートセットの最適化もいくつかあります
public static String FindLasstEntryWithGuavaIterable() {
return Iterables.getLast(linkedmap.entrySet()).getValue();
}
ここに完全なソースコードがあります
import com.google.common.collect.Iterables;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
public class PerformanceTest {
private static long startTime;
private static long endTime;
private static LinkedHashMap<Integer, String> linkedmap;
public static void main(String[] args) {
linkedmap = new LinkedHashMap<Integer, String>();
linkedmap.put(12, "Chaitanya");
linkedmap.put(2, "Rahul");
linkedmap.put(7, "Singh");
linkedmap.put(49, "Ajeet");
linkedmap.put(76, "Anuj");
//call a useless action so that the caching occurs before the jobs starts.
linkedmap.entrySet().forEach(x -> {});
startTime = System.nanoTime();
FindLasstEntryWithArrayListMethod();
endTime = System.nanoTime();
System.out.println("FindLasstEntryWithArrayListMethod : " + "took " + new BigDecimal((endTime - startTime) / 1000000.000).setScale(3, RoundingMode.CEILING) + " milliseconds");
startTime = System.nanoTime();
FindLasstEntryWithArrayMethod();
endTime = System.nanoTime();
System.out.println("FindLasstEntryWithArrayMethod : " + "took " + new BigDecimal((endTime - startTime) / 1000000.000).setScale(3, RoundingMode.CEILING) + " milliseconds");
startTime = System.nanoTime();
FindLasstEntryWithReduceMethod();
endTime = System.nanoTime();
System.out.println("FindLasstEntryWithReduceMethod : " + "took " + new BigDecimal((endTime - startTime) / 1000000.000).setScale(3, RoundingMode.CEILING) + " milliseconds");
startTime = System.nanoTime();
FindLasstEntryWithSkipFunctionMethod();
endTime = System.nanoTime();
System.out.println("FindLasstEntryWithSkipFunctionMethod : " + "took " + new BigDecimal((endTime - startTime) / 1000000.000).setScale(3, RoundingMode.CEILING) + " milliseconds");
startTime = System.currentTimeMillis();
FindLasstEntryWithGuavaIterable();
endTime = System.currentTimeMillis();
System.out.println("FindLasstEntryWithGuavaIterable : " + "took " + (endTime - startTime) + " milliseconds");
}
public static String FindLasstEntryWithReduceMethod() {
return linkedmap.entrySet().stream().reduce((first, second) -> second).orElse(null).getValue();
}
public static String FindLasstEntryWithSkipFunctionMethod() {
final long count = linkedmap.entrySet().stream().count();
return linkedmap.entrySet().stream().skip(count - 1).findFirst().get().getValue();
}
public static String FindLasstEntryWithGuavaIterable() {
return Iterables.getLast(linkedmap.entrySet()).getValue();
}
public static String FindLasstEntryWithArrayListMethod() {
List<Entry<Integer, String>> entryList = new ArrayList<Map.Entry<Integer, String>>(linkedmap.entrySet());
return entryList.get(entryList.size() - 1).getValue();
}
public static String FindLasstEntryWithArrayMethod() {
return String.valueOf(linkedmap.entrySet().toArray()[linkedmap.size() - 1]);
}
}
各メソッドのパフォーマンスを含む出力は次のとおりです
FindLasstEntryWithArrayListMethod : took 0.162 milliseconds
FindLasstEntryWithArrayMethod : took 0.025 milliseconds
FindLasstEntryWithReduceMethod : took 2.776 milliseconds
FindLasstEntryWithSkipFunctionMethod : took 3.396 milliseconds
FindLasstEntryWithGuavaIterable : took 11 milliseconds
LinkedHashMap
現在の実装(Java 8)はその末尾を追跡しています。パフォーマンスが気になる場合やマップのサイズが大きい場合は、リフレクションを介してそのフィールドにアクセスできます。
実装が変更される可能性があるため、フォールバック戦略も用意することをお勧めします。例外がスローされたときに何かをログに記録すると、実装が変更されたことがわかります。
次のようになります。
public static <K, V> Entry<K, V> getFirst(Map<K, V> map) {
if (map.isEmpty()) return null;
return map.entrySet().iterator().next();
}
public static <K, V> Entry<K, V> getLast(Map<K, V> map) {
try {
if (map instanceof LinkedHashMap) return getLastViaReflection(map);
} catch (Exception ignore) { }
return getLastByIterating(map);
}
private static <K, V> Entry<K, V> getLastByIterating(Map<K, V> map) {
Entry<K, V> last = null;
for (Entry<K, V> e : map.entrySet()) last = e;
return last;
}
private static <K, V> Entry<K, V> getLastViaReflection(Map<K, V> map) throws NoSuchFieldException, IllegalAccessException {
Field tail = map.getClass().getDeclaredField("tail");
tail.setAccessible(true);
return (Entry<K, V>) tail.get(map);
}
ClassCastException
のcatch
場合だけtail
ではありませんEntry
サブクラス(または将来の実装)で。
LinkedHashMapの最初と最後のエントリを取得するもう1つの方法は、Setインターフェースの「toArray」メソッドを使用することです。
ただし、エントリセットのエントリを繰り返し処理して、最初と最後のエントリを取得する方が良い方法だと思います。
配列メソッドを使用すると、「...に準拠するには、チェックされていない変換が必要です」という警告が表示されます。これは修正できません[@SuppressWarnings( "unchecked")アノテーションを使用することでのみ抑制できます)。
「toArray」メソッドの使用法を示す小さな例を以下に示します。
public static void main(final String[] args) {
final Map<Integer,String> orderMap = new LinkedHashMap<Integer,String>();
orderMap.put(6, "Six");
orderMap.put(7, "Seven");
orderMap.put(3, "Three");
orderMap.put(100, "Hundered");
orderMap.put(10, "Ten");
final Set<Entry<Integer, String>> mapValues = orderMap.entrySet();
final int maplength = mapValues.size();
final Entry<Integer,String>[] test = new Entry[maplength];
mapValues.toArray(test);
System.out.print("First Key:"+test[0].getKey());
System.out.println(" First Value:"+test[0].getValue());
System.out.print("Last Key:"+test[maplength-1].getKey());
System.out.println(" Last Value:"+test[maplength-1].getValue());
}
// the output geneated is :
First Key:6 First Value:Six
Last Key:10 Last Value:Ten
少し汚いですがremoveEldestEntry
、LinkedHashMap のメソッドをオーバーライドできます。これは、プライベートの匿名メンバーとして行うのに適している場合があります。
private Splat eldest = null;
private LinkedHashMap<Integer, Splat> pastFutures = new LinkedHashMap<Integer, Splat>() {
@Override
protected boolean removeEldestEntry(Map.Entry<Integer, Splat> eldest) {
eldest = eldest.getValue();
return false;
}
};
そのため、eldest
メンバーの最初のエントリーをいつでも取得できます。を実行するたびに更新されますput
。
また、オーバーライドput
して設定するのも簡単でなければなりませyoungest
ん...
@Override
public Splat put(Integer key, Splat value) {
youngest = value;
return super.put(key, value);
}
ただし、エントリの削除を開始すると、すべてが壊れます。それをだらだらする方法を理解していません。
他の方法で頭または尾に賢明な方法でアクセスできないのは非常に不愉快です...
おそらくこのようなもの:
LinkedHashMap<Integer, String> myMap;
public String getFirstKey() {
String out = null;
for (int key : myMap.keySet()) {
out = myMap.get(key);
break;
}
return out;
}
public String getLastKey() {
String out = null;
for (int key : myMap.keySet()) {
out = myMap.get(key);
}
return out;
}
提案:
map.remove(map.keySet().iterator().next());
私が使用することをお勧めしますConcurrentSkipListMapの持っているfirstKey()
とlastKey()
方法を
linkedHashMapは、最初、最後、または特定のオブジェクトを取得するメソッドを提供していません。
しかし、取得するのはかなり簡単です:
現在、alオブジェクトでイテレータを使用しています。任意のオブジェクトを取得できます。
ええ、私は同じ問題に遭遇しましたが、幸いにも最初の要素だけが必要です...-これは私がそれのためにしたことです。
private String getDefaultPlayerType()
{
String defaultPlayerType = "";
for(LinkedHashMap.Entry<String,Integer> entry : getLeagueByName(currentLeague).getStatisticsOrder().entrySet())
{
defaultPlayerType = entry.getKey();
break;
}
return defaultPlayerType;
}
最後の要素も必要な場合-私はマップの順序を逆にする方法を調べます-それを一時変数に保存し、反転したマップの最初の要素にアクセスします(したがって、それが最後の要素になります)、一時変数。
ハッシュマップを逆順で並べる方法について、いくつかの良い答えがあります:
上記のリンクからのヘルプを使用する場合は、賛成票を投じてください:)これが誰かの役に立つことを願っています。
public static List<Fragment> pullToBackStack() {
List<Fragment> fragments = new ArrayList<>();
List<Map.Entry<String, Fragment>> entryList = new ArrayList<>(backMap.entrySet());
int size = entryList.size();
if (size > 0) {
for (int i = size - 1; i >= 0; i--) {// last Fragments
fragments.add(entryList.get(i).getValue());
backMap.remove(entryList.get(i).getKey());
}
return fragments;
}
return null;
}