How to retrieve an element from HashMap by its position, is it possible at all?
Use a LinkedHashMap and when you need to retrieve by position, convert the values into an ArrayList.
LinkedHashMap<String,String> linkedHashMap = new LinkedHashMap<String,String>();
/* Populate */
linkedHashMap.put("key0","value0");
linkedHashMap.put("key1","value1");
linkedHashMap.put("key2","value2");
/* Get by position */
int pos = 1;
String value = (new ArrayList<String>(linkedHashMap.values())).get(pos);
HashMaps do not preserve ordering:
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.
Take a look at LinkedHashMap, which guarantees a predictable iteration order.
If you want to maintain the order in which you added the elements to the map, use LinkedHashMap as opposed to just HashMap.
Here is an approach that will allow you to get a value by its index in the map:
public Object getElementByIndex(LinkedHashMap map,int index){
return map.get( (map.keySet().toArray())[ index ] );
}
If you, for some reason, have to stick with the hashMap, you can convert the keySet to an array and index the keys in the array to get the values in the map like so:
Object[] keys = map.keySet().toArray();
You can then access the map like:
map.get(keys[i]);
Use LinkedHashMap:
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.
Use LinkedHashMap and use this function.
private LinkedHashMap<Integer, String> map = new LinkedHashMap<Integer, String>();
Define like this and.
private Entry getEntry(int id){
Iterator iterator = map.entrySet().iterator();
int n = 0;
while(iterator.hasNext()){
Entry entry = (Entry) iterator.next();
if(n == id){
return entry;
}
n ++;
}
return null;
}
The function can return the selected entry.
By default, java LinkedHasMap does not support for getting value by position. So I suggest go with customized IndexedLinkedHashMap
public class IndexedLinkedHashMap<K, V> extends LinkedHashMap<K, V> {
private ArrayList<K> keysList = new ArrayList<>();
public void add(K key, V val) {
super.put(key, val);
keysList.add(key);
}
public void update(K key, V val) {
super.put(key, val);
}
public void removeItemByKey(K key) {
super.remove(key);
keysList.remove(key);
}
public void removeItemByIndex(int index) {
super.remove(keysList.get(index));
keysList.remove(index);
}
public V getItemByIndex(int i) {
return (V) super.get(keysList.get(i));
}
public int getIndexByKey(K key) {
return keysList.indexOf(key);
}
}
Then you can use this customized LinkedHasMap as
IndexedLinkedHashMap<String,UserModel> indexedLinkedHashMap=new IndexedLinkedHashMap<>();
TO add Values
indexedLinkedHashMap.add("key1",UserModel);
To getValue by index
indexedLinkedHashMap.getItemByIndex(position);
I'm assuming by 'position' you're referring to the order in which you've inserted the elements into the HashMap. In that case you want to be using a LinkedHashMap. The LinkedHashMap doesn't offer an accessor method however; you will need to write one like
public Object getElementAt(LinkedHashMap map, int index) {
for (Map.Entry entry : map.entrySet()) {
if (index-- == 0) {
return entry.value();
}
}
return null;
}
Another working approach is transforming map values into an array and then retrieve element at index. Test run of 100 000 element by index searches in LinkedHashMap of 100 000 objects using following approaches led to following results:
//My answer:
public Particle getElementByIndex(LinkedHashMap<Point, Particle> map,int index){
return map.values().toArray(new Particle[map.values().size()])[index];
} //68 965 ms
//Syd Lambert's answer:
public Particle getElementByIndex(LinkedHashMap<Point, Particle> map,int index){
return map.get( (map.keySet().toArray())[ index ] );
} //80 700 ms
All in all retrieving element by index from LinkedHashMap seems to be pretty heavy operation.
HashMap - and the underlying data structure - hash tables, do not have a notion of position. Unlike a LinkedList or Vector, the input key is transformed to a 'bucket' where the value is stored. These buckets are not ordered in a way that makes sense outside the HashMap interface and as such, the items you put into the HashMap are not in order in the sense that you would expect with the other data structures
HashMap has no concept of position so there is no way to get an object by position. Objects in Maps are set and get by keys.
HashMaps don't allow access by position, it only knows about the hash code and and it can retrieve the value if it can calculate the hash code of the key. TreeMaps have a notion of ordering. Linkedhas maps preserve the order in which they entered the map.
you can use below code to get key :
String [] keys = (String[]) item.keySet().toArray(new String[0]);
and get object or list that insert in HashMap with key of this item like this :
item.get(keys[position]);
You can try to implement something like that, look at:
Map<String, Integer> map = new LinkedHashMap<String, Integer>();
map.put("juan", 2);
map.put("pedro", 3);
map.put("pablo", 5);
map.put("iphoncio",9)
List<String> indexes = new ArrayList<String>(map.keySet()); // <== Parse
System.out.println(indexes.indexOf("juan")); // ==> 0
System.out.println(indexes.indexOf("iphoncio")); // ==> 3
Related
Currently I have sorted my Hashmap on the values field.
I need to count the number of entries associated with each value in the hashmap.
Initially i thought of iterating over the sorted hashmap and counting the number of entries till the value did not change. In order to get the next value, I need to get to the next entry, but there is no way to do that till one loop iteration ends.
But I was just lost in the logic and could not proceed. :(
I tried the other logic which uses filters in stream().
Applying the filter on the values being 1 to 50 and then counting the entries which satisfy the predicate.
for(int i = 1; i < COUNT; i++){
int count = (int) single_count.entrySet().stream().filter(v -> v.getValue() == 1).count(); //collect(Collectors.toList());
unigram_Nc.put(i, count);
}
In this case I was aware of the values in the hashmap. But I would like to know the generic solution which returns the number of entries in a hashmap corresponding to each value.
Is there any other way to count the number of entries having a particular value without knowing the values before hand ?
You could do this much easier with the java 8 stream api.
For this you should take the values from your map: map.values()
With .stream() you get the stream for this collection.
then you can use the collect method with a groupingBy collector.
Finally it could look something like this:
final Map<Integer, Long> counts = map.values() // get the values
.stream() // get the stream
.collect(
Collectors.groupingBy( // the result should be grouped
o -> o, // the key of the result map is just the value
Collectors.counting() // the value of result map is the count
)
);
For older JDKs you can count like this:
Create a class and override its equals() and hashcode() method. Create a field of your preferred type say A and add another int type field to count.
1) Your hashcode() method should return the hash value of your field A.
2) In your equals() method, increase the value of count by 1 and set the count as value
Now create 2 hashmaps, first will have your initial map's value as keys. The second one will have the result of all the counts of values.
Refer to the below snippet:
class A
{
Integer count = 1;
String name;
#override
public int hashcode()
{
return name.hash();
}
#override
public boolean equals(Object obj)
{
obj.count++;
secondmap.put(obj.name, obj.count);
return true;
}
}
Now in your main class:
static firstmap = new ConcurrentMap<A, Integer>();
static secondmap = new ConcurrentMap<String, Integer>();
iterate over yourmap
{
put the value in firstmap as firstmap.put(yourmap value, 0);
}
At the end of iteration you will have all the count of values in the secondmap.
Note: If your initial map was having different signature then you can explicitly set the value of String name via A's constructor.
This was just an example, the actual implementation may differ a bit according your solution however you can refer to this logic. Also while creating your initial map you can implement this. This will save you the trouble of iterating again.
try this simple logic
Map<String,Integer> dataMap=new LinkedHashMap<String,Integer>(); //Your data map
Map<Integer,Integer> countMap=new LinkedHashMap<Integer,Integer>(); //map to count data map entries
//initializing with default value
dataMap.put("a", 1);
dataMap.put("b", 2);
dataMap.put("c", 1);
dataMap.put("d", 2);
dataMap.put("e", 1);
dataMap.put("f", 3);
dataMap.put("g", 1);
//main logic
dataMap.forEach( (k,v) -> {
if(countMap.get(v)==null)
countMap.put(v, 0);
Integer count=countMap.get(v);
countMap.put(v,count+1);
} );
//printing the count
countMap.forEach( (k,v) -> {
System.out.println(k+" "+v);
} );
This question already has answers here:
Iterating through a LinkedHashMap in reverse order
(6 answers)
Closed 7 years ago.
I have a LinkedHashMap (because the order of entry is important).
I want to be able to iterate over it's entries (key, value pairs) like an array
from end to start so the foreach methods doesn't fit here
something like :
for (int i = DestIndexStartPair.entrySet().size() , i> 0 ; i--) {
entry = DestIndexStartPair.entrySet()[i];
String Endsection = output.substring(entry.value());
System.out.println(Endsection );
}
There is no efficient way to iterate over a Set (such as entrySet) in reverse order. If you need iteration in both directions, then for the opposite direction the best approach is to copy into a temporary list and iterate the list in reverse.
Of course, if you only need one direction, then you should just ensure the LinkedHashMap has that order instead of the opposite.
Working solution:
List<Entry<Foo,Bar>> list = new ArrayList<Entry<Foo,Bar>>(map.entries());
for (int i = list.size() - 1; i >= 0; i--) {
Entry<Foo,Bar> entry = list.get(i);
}
Obviously, the trade off here is that you have to copy the whole map into the array list. If your map is too big (whatever is too big), you might have performance and memory problems.
Looking at map implementation might help more. May be by overriding in more appropriate way this can be achieved in balanced way as in performance or thread safety etc. But here is small hack that may help,
public class HackedLinkedHashMap<K,V> extends LinkedHashMap<K,V> implements Map<K,V> {
private LinkedList<K> keyList = new LinkedList<>();
#Override
public V put(K key, V value){
V obj = super.put(key, value);
keyList.addFirst(key);
return obj;
}
public LinkedList<K> getReversedKeyList(){
return keyList;
}}
public static void main(String[] args) {
System.out.println("Test conference");
HackedLinkedHashMap<Integer, Integer> map = new HackedLinkedHashMap();
for(Integer i=0;i<100;i++){
map.put(i, i);
}
Iterator<Integer> iterator = map.getReversedKeyList().iterator();
while (iterator.hasNext()){
System.out.println(iterator.next());
}
}
An EntrySet is a Set and thus doesn't normally have an index.
So, what you need would be...
for(Entry<K,V> entry : DestIndexStartPair.entrySet()) {
String Endsection = output.substring(entry.value()); // whatever output is
System.out.println(Endsection );
}
...and then store the result, and reverse it.
I have this HashMap containing words and the count for each word from a given text file;
{word=1, word2=1, word3=2, word4=1, word5=1, word6=4, word7=1, word8=1};
i was following your suggestion in other topics; but i have notice that if use fro example sorted Collections and i search for a specific KEY which could be 1 in this case it only return me one word while instead can return more values for same key;
the point is between all the collections:
Lists
Maps
ArrayLists
Trees
HashMaps
HashTables
which is the most advisable to use?
on my Class the user will input an int and that int will correspond to the 1st or 2nd or 3rd or 4th and so on..... words used in the files base on the count and occurences;
it's challenging
so far i have managed to store in hashmap and eventually order it in a Tree by Desc Key; so first element will be the greater; but still the algorithm needs more sense;
ps. i do not expect solution or pieces of codes but a good input to start ... a very good advise or direction best to follow;
Maps, by nature, store (will return) only one element per key. That means that if you'll store [key:1, val:a] and then store again [key:1, val:2]. The second insertion will override the first and when you'll "get" key:1 the returned result will be b.
You can, however, to store a List per key. This list can store all the value values per the same key.
So we'll declare the map that we'l use as follows:
Map<String, LinkedList<String>> map = new HashMap<>();
This is how insert should look like:
public void insert(String key, String value){
List<String> values = map.get(key);
if (values == null){ // this is the first time we use this key
values = new LinkedList<String>(); // so we need to create a new values List
}
values.add(value);
map.put(key, values)
}
the "get" is pretty straightforward:you get the list of values and if it's not null - iterate the values and print/do whatever you want with them.
public List<String> get(String key){
return map.get(key);
}
If I understand you correctly, you have a Map<String,Integer> map; which maps words to their frequencies, and now you want to look up words by frequency.
Create a new map that Map<Integer,List<String>> and fill it using the first map:
Map<Integer,List<String>> reverseMap = new HashMap<>();
for (Map.Entry<String,Integer> entry : map.entrySet()) {
List<String> list = reverseMap.get(entry.getValue());
if (list == null) {
reverseMap.put(entry.getValue(), list = new ArrayList<>());
}
list.add(entry.getKey());
}
You will get a map like:
java.util.HashMap[3] {
1=[word2, word4, word, word5, word7, word8]
2=[word3]
4=[word6]
}
In this map, each key is the frequency, each value is a list of words having that frequency.
Edit: To pull out the words having the second-most used frequency ("rank 2"), generate a list of the most used frequencies:
List<Integer> frequencies = new ArrayList<>(reverseMap.keySet());
Collections.sort(frequencies, Collections.reverseOrder());
Then:
System.out.println(reverseMap.get(frequences.get(2 - 1)));
Or, to sort the entire map in descending order of frequency (4, 2, 1), declare it as a TreeMap instead of a HashMap, with a reverseOrder comparator:
Map<Integer,List<String>> reverseMap = new TreeMap<>(Collections.reverseOrder());
I have this Java Map:
Can you tell me how I can get the 6-th element of the Map?
private static final Map<String, Users> cache = new HashMap<>();
is this possible? Or I have to use another Java collection?
Though a bit late to answer. But the option is to use LinkedHashMap: this map preserves the order according to insertion of elements, as everyone has suggested. However, As a warning, it has a constructor LinkedHashMap(int initialCapacity, float loadFactor, boolean accessOrder) which will create a linked hash map whose order of iteration is the order in which its entries were last accessed. Don't use this constructor for this case.
However, if I needed such functionality, i would extend it and implement my necessary function to re-use them in OOP way.
class MyLinkedMap<K, V> extends LinkedHashMap<K, V>
{
public V getValue(int i)
{
Map.Entry<K, V>entry = this.getEntry(i);
if(entry == null) return null;
return entry.getValue();
}
public Map.Entry<K, V> getEntry(int i)
{
// check if negetive index provided
Set<Map.Entry<K,V>>entries = entrySet();
int j = 0;
for(Map.Entry<K, V>entry : entries)
if(j++ == i)return entry;
return null;
}
}
Now i can instantiate it and can get a entry and value either way i want:
MyLinkedMap<String, Integer>map = new MyLinkedMap<>();
map.put("a first", 1);
map.put("a second", 2);
map.put("a third", 3);
System.out.println(map.getValue(2));
System.out.println(map.getEntry(1));
Output:
3
a second=2
HashMap doesn't grantee the order. If you concern about order you should use LinkedHashMap
Map<String, Users> orderedMap=new LinkedHashMap<>();
Now when you put an element it will keep the order what you put.
If you want to get 6th element, now you can do it since you have your elements in order.
orderedMap.values().toArray()[5]// will give you 6th value in the map.
Example
Map<String, String> orderedMap=new LinkedHashMap<>();
orderedMap.put("a","a");
orderedMap.put("b","b");
System.out.println(orderedMap.values().toArray()[1]); // you will get b(value)
System.out.println(orderedMap.keySet().toArray()[1]); // you will get b(key)
}
A HashMap does not maintain the order of the elements inserted in it. You can used a LinkedHashMap instead which maintains the order of the elements inserted in it.
Though you need to note that even a LinkedHashMap has no such method which would give the element at a particular index. You will have to manually iterate through the entries and extract the element at the 6th iteration.
With guava's Iterables
Iterables.get(map.entrySet(),6);
The HashMap has no defined ordering of keys.It's Unordered.
You can use LinkedHashMap which will store your keys in order of insertion.You can retrieve them by calling keySet().
HashMaps do not preserve ordering:
LinkedHashMap which guarantees a predictable iteration order.
Example
public class Users
{
private String Id;
public String getId()
{
return Id;
}
public void setId(String id)
{
Id = id;
}
}
Users user;
LinkedHashMap<String,Users> linkedHashMap = new LinkedHashMap<String,Users>();
for (int i = 0; i < 3; i++)
{
user = new Users();
user.setId("value"+i);
linkedHashMap.put("key"+i,user);
}
/* Get by position */
int pos = 1;
Users value = (new ArrayList<Users>(linkedHashMap.values())).get(pos);
System.out.println(value.getId());
According to documentation, HashMap is a 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.
That's why it is not wise to use this kind of Collection.
UPDATE:
Based on #Prateek implementation of LinkedHashMap I would suggest something like:
LinkedHashMap<String,User> linkedHashMap = new LinkedHashMap<String,User>();
// or LinkedHashMap<String,User> linkedHashMap = new LinkedHashMap<>(); //for java 7+
linkedHashMap.put("1",userObj1);
linkedHashMap.put("2",userObj2);
linkedHashMap.put("3",userObj3);
/* Get by position */
int pos = 1; // Your position
User tmp= (new ArrayList<User>(linkedHashMap.values())).get(pos);
System.out.println(tmp.getName());
A HashMap doesn't have a position. You can iterate through its KeySet or EntrySet, and pick the nth element, but it's not really the same as a position. A LinkedHashMap does have a position, since it has a predictable iteration order.
You need to use a LinkedHashMap in order to be able to tell the order of the inserted elements. HashMap is not capable of doing so.
There is no Order in HashMap. You can obtain the list of may keys using map.keySet() but there's no guarantee the key set will be in the order which you add it in. Use LinkedHashMap instead of HashMap It will always return keys in same order (as insertion)
Correct!!
you will have to use other collection for getting values on index(position).
You can use ArrayList
If the ordering is to mean anything significant, you could consider using a SortedMap.
Concrete implementation: TreeMap
Use LinkedHashMap instead of HashMap It will return keys in same order (as insertion) when calling keySet().
For mare detail about LinkedHashMap see this
For example to get the element from specific index
Create a new list from your values and get the value based on index.
LinkedHashMap<String, List<String>> hMap;
List<List<String>> l = new ArrayList<List<String>>(hMap.values());
l.get(6);
What is the most elegant way to copy keys and values from one hashtable to another between start and end keys in inverse order? For example original hashtable is:
[<1,"object1">; <2, "object2">; <4,"object3">; <5,"object4">;<7,"object5">;<8,"object6">]
after calling function getPartListOfNews(2,4) it should return hashtable like this:
[<7,"object5">;<5,"object4">;<4,"object3">]
I had made code to do it and it comes below, but I don't think is this a better way to do what i had described before. Is there ara any better solutions? How can I simplify this code?
public Hashtable<Integer, News> getPartListOfNews(int start, int end){
Hashtable <Integer, News> tempNewsList = new Hashtable <Integer, News>();
int total_to_get = end-start;
int list_size = newsList.size();
Object[] key_array = new Object[list_size];
if(list_size < total_to_get){
return newsList;
}
else{
Enumeration e = newsList.keys();
int index=0;
while(e.hasMoreElements()){
key_array[index] = e.nextElement();
index ;
}
for (int i=end; i>start; i--){
tempNewsList.put((Integer)key_array[i], newsList.get(key_array[i]));
}
return tempNewsList;
}
}
Update:
public Hashtable<Integer, News> newsList = new Hashtable<Integer, News>();
Thanks.
First, you need to use a LinkedHashMap in your newsList attribute, to preserve insertion order. Also, it's better if you declare attributes and return values of methods using the Map interface instead of the concrete class used, in this way you can easily change the implementation, like this:
private Map<Integer, News> newsList = new LinkedHashMap<Integer, News>();
With the above in mind, here's my shot at solving your problem:
public Map<Integer, News> getPartListOfNews(int start, int end) {
// first, get the range of keys from the original map
List<Integer> keys = new ArrayList<Integer>();
for (Integer key : newsList.keySet()) // iterates in insertion order
keys.add(key);
List<Integer> subkeys = keys.subList(start, end);
// now add them in the required order
Map<Integer, News> tempNewsList = new LinkedHashMap<Integer, News>();
ListIterator<Integer> iter = subkeys.listIterator();
while (iter.hasPrevious()) {
Integer key = iter.previous();
tempNewsList.put(key, newsList.get(key));
}
return tempNewsList;
}
First, your code does not have any effect. Hash table "breaks" the order. The order of elements in hash table depends on the particular hash implementation.
There are 2 types of Maps in JDK: HashMap and SortedMap (typically we use its implementation TreeMap). BTW do not use Hashtable: this is old, synchronized and almost obsolete implementation).
When you are using HashMap (and Hashtable) the order of keys is unpredictable: it depends on implementation of hashCode() method of class you are using as keys of your map. If you are using TreeMap you can use Comparator to change this logic.
If you wish your keys to be extracted in the same order you put them use LinkedHashMap.
I think a HashTable is not ordered. If you use a ordered data structure (such as LinkedHashMap) you could sort it (with java build-in methods) and make a sublist. this should be 2 lines of code and very efficiant.