Java Linkedhashmap Get First or Last Entry

Java LinkedHashMap get first or last entry

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.

how to conveniently get first element or last element from LinkedHashMap?

one way to do this:

    Map<String, Double> map = new LinkedHashMap<>();
map.put("one", 2.0);
map.put("two", 12.0);
map.put("three", 44.0);
String lKeyFirst = null;
String lKeyLast = null;
if (!map.isEmpty()){
lKeyFirst = map.keySet().iterator().next();
for(String key : map.keySet()){
lKeyLast = key;
}
System.out.println("First key: " +lKeyFirst);
System.out.println("Last key: " +lKeyLast);
}

Output:

First key: one

Last key: three

of course isEmpty is never false in this case.

EDIT:

@Test
public void testMapOneValue() {
Map<String, Double> map = new LinkedHashMap<>();
map.put("one", 2.0);
String lKeyFirst = null;
String lKeyLast = null;
if (!map.isEmpty()){
lKeyFirst = map.keySet().iterator().next();
for(String key : map.keySet()){
lKeyLast = key;
}
System.out.println("First key: " +lKeyFirst);
System.out.println("Last key: " +lKeyLast);
}
}

Output:

First key: one

Last key: one

Get the first item of linkedhashmap

You can use this to get the first element key:

 Object key = linkedHashMap.keySet().iterator().next();

then to get the value:

Object value = linkedHashMap.get(key);

and finally to remove that entry:

linkedHashMap.remove(key);

Accessing the last entry in a Map

To answer your question in one sentence:

Per default, Maps don't have a last entry, it's not part of their contract.


And a side note: it's good practice to code against interfaces, not the implementation classes (see Effective Java by Joshua Bloch, Chapter 8, Item 52: Refer to objects by their interfaces).

So your declaration should read:

Map<String,Integer> map = new HashMap<String,Integer>();

(All maps share a common contract, so the client need not know what kind of map it is, unless he specifies a sub interface with an extended contract).


Possible Solutions

Sorted Maps:

There is a sub interface SortedMap that extends the map interface with order-based lookup methods and it has a sub interface NavigableMap that extends it even further. The standard implementation of this interface, TreeMap, allows you to sort entries either by natural ordering (if they implement the Comparable interface) or by a supplied Comparator.

You can access the last entry through the lastEntry method:

NavigableMap<String,Integer> map = new TreeMap<String, Integer>();
// add some entries
Entry<String, Integer> lastEntry = map.lastEntry();

Linked maps:

There is also the special case of LinkedHashMap, a HashMap implementation that stores the order in which keys are inserted. There is however no interface to back up this functionality, nor is there a direct way to access the last key. You can only do it through tricks such as using a List in between:

Map<String,String> map = new LinkedHashMap<String, Integer>();
// add some entries
List<Entry<String,Integer>> entryList =
new ArrayList<Map.Entry<String, Integer>>(map.entrySet());
Entry<String, Integer> lastEntry =
entryList.get(entryList.size()-1);

Proper Solution:

Since you don't control the insertion order, you should go with the NavigableMap interface, i.e. you would write a comparator that positions the Not-Specified entry last.

Here is an example:

final NavigableMap<String,Integer> map = 
new TreeMap<String, Integer>(new Comparator<String>() {
public int compare(final String o1, final String o2) {
int result;
if("Not-Specified".equals(o1)) {
result=1;
} else if("Not-Specified".equals(o2)) {
result=-1;
} else {
result =o1.compareTo(o2);
}
return result;
}

});
map.put("test", Integer.valueOf(2));
map.put("Not-Specified", Integer.valueOf(1));
map.put("testtest", Integer.valueOf(3));
final Entry<String, Integer> lastEntry = map.lastEntry();
System.out.println("Last key: "+lastEntry.getKey()
+ ", last value: "+lastEntry.getValue());

Output:

Last key: Not-Specified, last value: 1

Solution using HashMap:

If you must rely on HashMaps, there is still a solution, using a) a modified version of the above comparator, b) a List initialized with the Map's entrySet and c) the Collections.sort() helper method:

    final Map<String, Integer> map = new HashMap<String, Integer>();
map.put("test", Integer.valueOf(2));
map.put("Not-Specified", Integer.valueOf(1));
map.put("testtest", Integer.valueOf(3));

final List<Entry<String, Integer>> entries =
new ArrayList<Entry<String, Integer>>(map.entrySet());
Collections.sort(entries, new Comparator<Entry<String, Integer>>(){

public int compareKeys(final String o1, final String o2){
int result;
if("Not-Specified".equals(o1)){
result = 1;
} else if("Not-Specified".equals(o2)){
result = -1;
} else{
result = o1.compareTo(o2);
}
return result;
}

@Override
public int compare(final Entry<String, Integer> o1,
final Entry<String, Integer> o2){
return this.compareKeys(o1.getKey(), o2.getKey());
}

});

final Entry<String, Integer> lastEntry =
entries.get(entries.size() - 1);
System.out.println("Last key: " + lastEntry.getKey() + ", last value: "
+ lastEntry.getValue());

}

Output:

Last key: Not-Specified, last value: 1

Get first LinkedHashMap key based on value in Java

Rather than checking containsValue first, use orElse on the optional returned by findFirst, which is one fewer iteration through the map.

int key = map.entrySet().stream()
.filter(entry -> entry.getValue() == 1)
.map(Map.Entry::getKey).findFirst().orElse(-1);

findFirst would return an empty optional if there is nothing left after the filter. This only happens if there is no value 1 in the map to begin with. orElse returns its argument, if the optional is empty, otherwise it returns the wrapped value.

getting last element from a linked hashmap returned from dao layer?

keySet() being executed on LinkedHashMap returns LinkedHashSet that is indeed Set but "remembers" the order of elements.

You can get the last element as following:

Map<TheType> map = .....
.................
TheType theLastKey = new ArrayList<>(map.keySet()).get(map.size() - 1)

Removing the first half of the entries in LinkedHashMap other than looping

There's no method in the class that makes this possible. The source code doesn't have any operations for ranges of keys or entries. Since the linking is built on top of the HashMap logic, individual entries still have to be individuatlly found by a hashed key lookup to remove them, so being able to remove a range couldn't be done faster in a LinkedHashMap, which is unlike the analogy of a LinkedList to an ArrayList.

For simpler code that's equivalent to what you're doing:

a.keys.take(a.size / 2).forEach(a::remove)

If you don't want to use a library for a cache set, LinkedHashSet is designed so you can easily build your own by subclassing. For instance, a basic one that simply removes the oldest entry when you add elements above a certain collection size:

class CacheHashMap<K, V>(private var maxSize: Int): LinkedHashMap<K, V>() {
override fun removeEldestEntry(eldest: MutableMap.MutableEntry<K, V>?): Boolean =
size == maxSize
}

Also, if you set accessOrder to true in your constructor call, it orders by last used to most recently used entry, which might be more apt for your situation than insertion order.



Related Topics



Leave a reply



Submit