Get first and last element from a HashMap - java

I have the following code and I'd like to get able to get the first and last element from the Map and assign each to a String.
String result1stElement = null;
String resultLastElement = null;
Map<String, String> result = new HashMap<String, String>();
result = myModel.getSampleResults();
Any ideas.
Thanks in advance.

First of all, Maps are not ordered so you wont really have a first and last element.
However, if you wish to get the first and last element of this anyways you could just get the values and convert this into an array. This isn't really pretty, but it'll work.
Map<String, String> result = new HashMap<String, String>();
result = myModel.getSampleResults();
map.values().toArray()[0]; //First result
map.values().toArray()[result.size()-1]; //Last result
Note: This is not tested with a compiler.

First and last element concepts not applicable to Hash-based structures like HashMap and HashSet.
Insertion or deletion of key may cause element reordering on-the-fly.
I guess your model results is an key-value pairs list, not hash map. In this case element ordering is in place. LinkedHashMap keeps insertion order of elements.
Replace HashMap to LinkedHashMap (and modify .getSampleResults()) to return LinkedHashMap and check this question for futher details Java LinkedHashMap get first or last entry .

HashMap has no such thing as order. From HashMap javadoc:
This class makes no guarantees as to the order of the map; in
particular, it does not guarantee that the order will remain constant
over time.
You'll have to use LinkedHashMap. Take a look at entrySet() method and this question+answer

"toArray" method of Set interface can be used.
But iterating over the entries in the entry set and getting the first and last entry is a better approach.
This example might be helpful:
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

There is no such a thing as a first and last element in a HashMap. This is the price you have to pay for O(1) lookup: internally the implementation will chuck your entries into a list of buckets in no easily identifiable (but deterministic) order. This process puts the Hash in HashMap, and in fact the more chaotic it is, the better the performance.
You can use a TreeMap if you want a map sorted by the natural order of its keys (or a custom comparator) or you can have a LinkedHashMap if you want the elements to be arranged in the order of insertion.
P.s.: even if you choose a Map implementation that maintains some kind of order, calling toArray() just to get the first and last elements is a massive overkill, I wouldn't do it. TreeMap has firstEntry() and lastEntry() methods, and even with LinkedHashMap, it's a lot cheaper to just manually iterate across the elements and keep the first and last one instead of allocating a potentially huge array.

Your comment to #Nikolay's answer shows an important detail of your question that was hidden until now.
So, you want to test a method which uses a HashMap structure for refering to some added objects and you want to test, if this method delivers some ordering in this structure? First added object shall remain at a "first position", last added object at a "last position"?
As the other answers already show, there is no way without refactoring that method. HashMap doesn't deliver any meaningful ordering at all and if that method should deliver some ordering, it is simply broken - implementation is faulty.
Of course, you can write a unit test using the algorithm provided by #Sander. This test will fail most of the time. And this again shows the fact, that the tested method has to be refactured like #Nikolay showed in his answer, for instance.

Related

How to insert another element into TreeMap value as a List

so im still learning about Java mapping and just wondering is it possible to insert another element into TreeMap value as a List? So here's my code:
TreeMap<String,List<Integer>> myTree = new TreeMap<>();
String info = "Andi 20";
Integer extra = 100;
String[] temp = info.split(" ");
myTree.put(temp[0], Collections.singletonList(Integer.parseInt(temp[1]))); // {Andi : [20]}
how to insert another element (for example : Integer extra) into a list of value? so the output will look like this :
// {Andi : [20,100]}
if it possible, maybe can you give the detail about the time complexity too?? it will help me a lot
Thank you everyone...
As long as the List implementation you're using supports add, of course you can add additional elements.
But, you're using Collections#singletonList, which by definition does not allow any modifications (the singleton collections utilities return immutable implementations). Just use ArrayList, LinkedList, etc.
Map<String,List<Integer>> map = new TreeMap<>();
map.put("foo", new ArrayList<>());
map.get("foo").add(1);
map.get("foo").add(2);
The time complexity for get and put are in the TreeMap documentation:
This implementation provides guaranteed log(n) time cost for the containsKey, get, put and remove operations.
The time complexity of map.get("foo").add(1) is log(n), because ArrayList#add is constant-time.
You can make use of Map#computeIfAbsent to handle initializing the List:
map.computeIfAbsent("foo", key -> new ArrayList<>()).add(1);
Note that computeIfAbsent is preferable to putIfAbsent in any case where new is used, because computeIfAbsent avoids an unnessary allocation when the key already exists in the map.

How to get key position from a HashMap in Java

How can I get the key position in the map? How can I see on which position is "Audi" and "BMW"?
Map<String, Integer> map = new HashMap<String, Integer>();
map.put("Audi", 3);
map.put("BMW", 5);
As other answers state you need to use a structure like java.util.LinkedHashMap. LinkedHashMap maintains its keys internally using a LinkedEntrySet, this does not formally provide order, but iterates in the insertion order used.
If you pass the Map.keySet() into a List implementation you can make use of the List.indexOf(Object) method without having to write any of the extra code in the other answer.
Map<String, Integer> map = new LinkedHashMap<String, Integer>();
map.put("Audi", 3);
map.put("BMW", 5);
map.put("Vauxhall", 7);
List<String> indexes = new ArrayList<String>(map.keySet()); // <== Set to List
// BOOM !
System.out.println(indexes.indexOf("Audi")); // ==> 0
System.out.println(indexes.indexOf("BMW")); // ==> 1
System.out.println(indexes.indexOf("Vauxhall")); // ==> 2
You can't. The keys on a Map and a HashMap are not ordered. You'll need to use a structure that preserves order, such as a LinkedHashMap.
Note that LinkedHashMap does not provide a method that gets keys by position, so this is only appropriate if you are going to be using an iterator.
The alternative is to create a second Map that maps from your key to the Integer position, and add to it as you go along:
Map<String, Integer> indexMap = new HashMap<String, Integer>();
indexMap.put("Audi", 0);
indexMap.put("BMW", 1);
For a more elegant solution, you might need to give more information about what you're doing.
You can't. From the HashMap JavaDocs:
Hash table based implementation of the Map interface. This implementation provides all of the optional map operations, and permits null values and the null key. (The HashMap class is roughly equivalent to Hashtable, except that it is unsynchronized and permits nulls.) This class makes no guarantees as to the order of the map; in particular, it does not guarantee that the order will remain constant over time.
So, the order may vary between iterations. If you need to preserve the order you can take a look at LinkedHashMap
From the LinkedHashMap JavaDocs:
Hash table and linked list implementation of the Map interface, with predictable iteration order. This implementation differs from HashMap in that it maintains a doubly-linked list running through all of its entries. This linked list defines the iteration ordering, which is normally the order in which keys were inserted into the map (insertion-order).
So, to find the key position you basically need to iterate the keys and count the position of the key you are searching for.
On a side note, IMO this may not be the best use of the Map datatype. I believe that if you really need the position you should use some type of List (e.g. ArrayList) that actually preserves the order and you can use the get method to retrieve elements for a certain index.

Retrieve N most relevant objects in Java TreeMap

According to this question I have ordered a Java Map, as follows:
ValueComparator bvc = new ValueComparator(originalMap);
Map<String,Integer> sortedMap = new TreeMap<String,Integer>(bvc);
sortedMap.putAll(originalMap);
Now, I would like to extract the K most relevant values from the map, in top-K fashion. Is there a highly efficient way of doing it without iterating through the map?
P.S., some similar questions (e.g., this) ask for a solution to the top-1 retrieval problem.
No, not if you use a Map. You'd have to iterate over it.
Have you considered using a PriorityQueue? It's Java's implementation of a heap. It has efficient operations for insertion of arbitrary elements and for removal of the "minimum". You might think about doing this here. Instead of a Map, you could put them into a PriorityQueue ordered by relevance, with the most relevant as the root. Then, to extract the K most relevant, you'd just pop K elements from the PriorityQueue.
If you need the map-like property (mapping from String to Integer), then you could write a class that internally keeps everything in both a PriorityQueue and a HashMap. When you insert, you insert into both; when you remove the minimal element, you pop from the PriorityQueue, and that then tells you which element you also need to remove from your HashMap. This will still give you log-time inserts and min-removals.

HashMap returns value in non sequential order

I am inserting four values with different keys in a HashMap.
Code Snippet :
HashMap<Integer, String> choice = new HashMap<Integer, String>();
choice.put(1, "1917");
choice.put(2, "1791");
choice.put(3, "1902");
choice.put(4, "1997");
But when I am printing that map values,it returns a result something like :
{4=1997, 1=1917, 2=1791, 3=1902}
How can I get the map values in a sequential order the way I have put/inserted?
You can use a LinkedHashMap instead, which will keep the insertion order:
This implementation differs from HashMap in that it maintains a doubly-linked list running through all of its entries. This linked list defines the iteration ordering, which is normally the order in which keys were inserted into the map (insertion-order).
You can modify your code like this:
Map<Integer, String> choice = new LinkedHashMap<Integer, String>();
//rest of the code is the same
LinkedHashMap, which is a Hash table and linked list implementation of the Map interface can be used.
It maintains the same order in which the values are inserted using doubly linked list.
Reference : http://docs.oracle.com/javase/1.4.2/docs/api/java/util/LinkedHashMap.html
[Edit]What the OP asks is not entirely clear to me. The OP could be asking, "How do I retrieve items from a map in insertion order?" If that is what the OP meant, then the following information is not a solution.
If the OP is asking, "How do I retrieve items from a Hash sorted by the key?" then the following is on-point. Getting the sorted keys of a hash/associative array is a common operation.
The answer can be found in how to sort Map values by key in Java:
List sortedKeys=new ArrayList(yourMap.keySet());
Collections.sort(sortedKeys);
If you care about the order in which the keys are stored and retrieved, consider using a TreeMap instead. Unless you have a very large number of elements (millions+), the performance difference is not likely to be noticeable.

Java - remove last known item from HASHMAP on MAP!s

OK so this is a BIT different. I have a new HashMap
private Map<String, Player> players = new HashMap<String, Player>();
How do I remove last known item from that? Maybe somethign like this?
hey = Player.get(players.size() - 1);
Player.remove(hey);
The problem is, a HashMap is not sorted like a list. The internal order depends on the hashCode() value of the key (e.g. String). You can use a LinkedHashMap which preserves the insert order. To remove the last entry on this you can use an iterator in combination with a counter which compares to the size and remove the last entry.
It's so easy. Try this:
Map<String, Player> players = new LinkedHashMap<String, Players>();
List<String> list = new ArrayList<String>(players.keySet());
map.remove(list.get(list.size()-1));
I'm a little bit confused. First of all, you're saying that you've got a new ArrayList and you're illustrating this with a line that creates a new HashMap. Secondly, does the Player class really have static methods like get(int) and remove(Object)?
HashMap doesn't have a particular order, ArrayList (as any other List) does.
Removing from an ArrayList
If you've got a list of players, then you can do the following:
private List<Player> players = new ArrayList<Player>();
// Populate the list of players
players.remove(players.size() - 1);
Here, I've used the remove(int) method of List, which allows to remove an item at an arbitrary index.
Removing from a HashMap
If you've got a map of players, there's no such thing as "the last item". Sure, you can iterate over the map and one of the items will pop out last, but that doesn't mean anything. Therefore, first you have to find out what you want to remove. Then you can do the following:
private Map<String, Player> players = new HashMap<String, Player>();
// Populate the map of players
// Find the key of the player to remove
players.remove(toRemove);
Here, I've used the remove(Object) method of Map. Note that in order to remove some key-value pair, you have to show the key, not the value.
There's no "first" and "last" in a HashMap. It's unordered. Everything is accessible by its key, not by index.
You cannot delete from HashMap like that. You need to use LinkedHashMap.
Simple, just do something of this effect.
1) Get a keyset iterator;
2) Create a Key somelastKey = null
3) Iterate through the iterator and assigning somelastKey until iterator finishes.
4) finally, do players.remove(somelastKey);
Bear in mind that HashMap is unordered, it depends on Object's hashCode to determine insertion order.
Instead of using HashMap, try using LinkedHashMap which keeps a predictable iteration order.
Hope this helps....
You'll probably have to extend HashMap, override put so that it caches the key, and then create a new method that just removes the key that was cached.
Unfortunately, this will only let you remove the most recently added. If you need to remove the most recently added multiple times (without inserting in-between the removes), you're out of luck.
In that case, I'd probably do the same overrides, just write the keys to a List. So you'd have both a list and a Map.
When adding:
String key; Player value;
lastKey = key;
map.put(key, value);
//...later...
Player lastAdded = map.remove(lastKey);
Other than that there's really no way without using a LinkedHashMap or in some way creating your own wrapper map or extending HashMap.
You shouldn't be using a raw hashmap anywhere because things like this happen.
Get in the habit of wrapping your collections in business logic classes.
See, in your case right now you need to associate these two related variables--your hashmap and a "Last entered" item so you can remove it.
If you need to remove the last item from some other class, you need to pass both items.
Any time you find yourself passing 2 or more items together into more than one API, you are probably missing a class.
Create a new class that contains the hashmap and a "lastAdded" variable. Have put and remove methods that are just forwarded to the hashmap, but the put method would also set the lastAdded variable.
Also be sure to add a removeLast() method.
NEVER allow access to your hashmap outside this class, it needs to be completely private (this is what I mean by wrapped). In this way you can ensure it doesn't get out of sync with the lastAdded variable (also completely private).
Just to reiterate getters and setters for these variables would be a terrible idea (as they are with nearly all actual OO code).
You will quickly find a bunch of other methods that NEED to be in this class in order to access data inside your hashmap--methods that never felt right in their current location. You will probably also notice that those methods always have an additional parameter or two passed in--those parameters should probably be members of your new class.
Once you get in the habit of doing actual OO design (via refactoring in this case), you'll find your code MUCH more manageable. To illustrate this point, if you find later that you need multiple levels of "delete last", it will be TRIVIAL to add to your class because it will be extremely clear exactly what methods can modify your hashtable and where your new "stack" of lastItems should be located--in fact it's probably a 2 line code change.
If you do not make this wrapper class, various locations will each have code to set "lastAdded" when they add code to the hashtable. Each of those locations will have to be modified, some may be in other classes requiring you to pass your new stack around with the hashtable. It will be easier to get them out of synch if you forget to change one location.

Categories