可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I have used LinkedHashMap
because it is important the order in which keys entered in the map.
But now I want to get the value of key in the first place (the first entered entry) or the last.
Should there be a method like first()
and last()
or something like that?
Do I need to have an iterator to just get the first key entry? That is why I used LinkedHashMap
!
Thanks!
回答1:
The semantics of LinkedHashMap
are still those of a Map, rather than that of a LinkedList
. It retains insertion order, yes, but that's an implementation detail, rather than an aspect of its interface.
The quickest way to get the "first" entry is still entrySet().iterator().next()
. Getting the "last" entry is possible, but will entail iterating over the whole entry set by calling .next()
until you reach the last. while (iterator.hasNext()) { lastElement = iterator.next() }
edit: However, if you're willing to go beyond the JavaSE API, Apache Commons Collections has its own LinkedMap
implementation, which has methods like firstKey
and lastKey
, which do what you're looking for. The interface is considerably richer.
回答2:
Can you try doing something like (to get the last entry):
linkedHashMap.entrySet().toArray()[linkedHashMap.size() -1];
it's O(N) :)
回答3:
LinkedHashMap
current implementation (Java 8) keeps track of its tail. If performance is a concern and/or the map is large in size, you could access that field via reflection.
Because the implementation may change it is probably a good idea to have a fallback strategy too. You may want to log something if an exception is thrown so you know that the implementation has changed.
It could look like:
public static Entry getFirst(Map map) { if (map.isEmpty()) return null; return map.entrySet().iterator().next(); } public static Entry getLast(Map map) { try { if (map instanceof LinkedHashMap) return getLastViaReflection(map); } catch (Exception ignore) { } return getLastByIterating(map); } private static Entry getLastByIterating(Map map) { Entry last = null; for (Entry e : map.entrySet()) last = e; return last; } private static Entry getLastViaReflection(Map map) throws NoSuchFieldException, IllegalAccessException { Field tail = map.getClass().getDeclaredField("tail"); tail.setAccessible(true); return (Entry) tail.get(map); }
回答4:
One more way to get first and last entry of a LinkedHashMap is to use "toArray" method of Set interface.
But I think iterating over the entries in the entry set and getting the first and last entry is a better approach.
The usage of array methods leads to warning of the form " ...needs unchecked conversion to conform to ..." which cannot be fixed [but can be only be suppressed by using the annotation @SuppressWarnings("unchecked")].
Here is a small example to demonstrate the usage of "toArray" method:
public static void main(final String[] args) { final Map orderMap = new LinkedHashMap(); orderMap.put(6, "Six"); orderMap.put(7, "Seven"); orderMap.put(3, "Three"); orderMap.put(100, "Hundered"); orderMap.put(10, "Ten"); final Set> mapValues = orderMap.entrySet(); final int maplength = mapValues.size(); final Entry[] 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
回答5:
It's a bit dirty, but you can override the removeEldestEntry
method of LinkedHashMap, which it might suit you to do as a private anonymous member:
private Splat eldest = null; private LinkedHashMap pastFutures = new LinkedHashMap() { @Override protected boolean removeEldestEntry(Map.Entry eldest) { eldest = eldest.getValue(); return false; } };
So you will always be able to get the first entry at your eldest
member. It will be updated every time you perform a put
.
It should also be easy to override put
and set youngest
...
@Override public Splat put(Integer key, Splat value) { youngest = value; return super.put(key, value); }
It all breaks down when you start removing entries though; haven't figured out a way to kludge that.
It's very annoying that you can't otherwise get access to head or tail in a sensible way ...
回答6:
I would recommend using ConcurrentSkipListMap which has firstKey()
and lastKey()
methods
回答7:
Perhaps something like this :
LinkedHashMap 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; }
回答8:
Suggestion:
map.remove(map.keySet().iterator().next());
回答9:
Though linkedHashMap doesn't provide any method to get first, last or any specific object.
But its pretty trivial to get :
- Map orderMap = new LinkedHashMap();
Set al = orderMap.keySet();
now using iterator on al object ; you can get any object.
回答10:
Yea I came across the same problem, but luckily I only need the first element... - This is what I did for it.
private String getDefaultPlayerType() { String defaultPlayerType = ""; for(LinkedHashMap.Entry entry : getLeagueByName(currentLeague).getStatisticsOrder().entrySet()) { defaultPlayerType = entry.getKey(); break; } return defaultPlayerType; }
If you need the last element as well - I'd look into how to reverse the order of your map - store it in a temp variable, access the first element in the reversed map(therefore it would be your last element), kill the temp variable.
Here's some good answers on how to reverse order a hashmap:
How to iterate hashmap in reverse order in Java
If you use help from the above link, please give them up-votes :) Hope this can help someone.