HashMap in Tree structure in Java - java

I am looking for a container that would basically work like HashMap where I could put and get any of the entries in O(1) time. I also want to be able to iterate through but I want the order to be sorted by values. So neither TreeMap nor LinkedHashMap would work for me. I found the example below:
SortedSet<Map.Entry<String, Double>> sortedSet = new TreeSet<Map.Entry<String, Double>>(
new Comparator<Map.Entry<String, Double>>() {
#Override
public int compare(Map.Entry<String, Double> e1,
Map.Entry<String, Double> e2) {
return e1.getValue().compareTo(e2.getValue());
}});
The problem is SortedSet doesn't have any get method to get entries.
I will be using this collection in a place where I will be adding entries but in case of already existing entry, the value(double) will be updated and then sorted again by using the comparator(which compares values as mentioned above). What can I use for my needs?

There is no such data structure in the Java class libraries.
But you could create one that is a wrapper for a private HashMap and a private TreeMap with the same set of key/value pairs.
This gives a data structure that has get complexity of O(1) like a regular HashMap (but not put or other update operations), and a key Set and entry Set which can be iterated in key order ... as requested in the original version of this Question.
Here is a start for you:
public class HybridMap<K,V> implements Map<K,V> {
private HashMap<K,V> hashmap = ...
private TreeMap<K,V> treemap = ...
#Override V get(K key) {
return hashmap.get(key);
}
#Override void (K key, V value) {
hashmap.put(key, value);
treemap.put(key, value);
}
// etcetera
}
Obviously, I've only implemented some of the (easy) methods.
If you want to be able to iterate the entries in value order (rather than key order), once again there is no such data structure in the Java class libraries.
In this case, wrapping a HashMap and TreeMap is going to be very complicated if you need the resulting Map to conform fully to the API contract.
So I suggest that you just use a HashMap and TreeSet of the key/value pairs ... and manually keep them in step.

Related

Add HashMap values in HashMap inside ArrayList without duplicate in Android

Set of values present in HashMap<key,value>. How to add HashMap value in HashMap<key,value> inside ArrayList by avoiding duplicate value in android.
Do you mean adding unique values from HashMap to ArrayList ?
If yes, you can add HashMap entries <K, V> to a reverse HashMap <V, K>, then get all the keys of this reverse map. Assume that your key has class type K and your value has class type V:
// change to private if needed
public List<V> getUniqueValues(Map<K, V> originMap) {
Map<V, K> reverseMap = new HashMap<>();
Set<K> keys = originMap.keySet();
Iterator<K> iterator = keys.iterator();
while (iterator.hasNext()) {
K key = iterator.next();
V val = originMap.get(key);
reverseMap.add(val, key);
}
return new ArrayList<>(reverseMap.keySet());
}
To add HashMap values inside array list use this approach:
Firstly declare it as below to flexibly add the values directly as a ArrayList
ArrayList<HashMap<key,value>>> myArrayHash = new ArrayList<HashMap<key,value>>
To add values into it:
If you have already created your HashMap from the sound of your question:
myArrayHash.add(HashMapValue);
To avoid the duplicates:
You need to use the Set Class in java so finally the code would amount as below:
Set<ArrayList<HashMap<key,value>>> hashset = new HashSet<>();
hashset.addAll(myArrayHash);
myArrayHash.clear();
myArrayHash.addAll(hashset);
You will need to replace your variable values appropriately since you havent posted any code. This is good enough example to set you up for a general example for any sort of such issues in future.

Sorting a HashMap by date

In a Java class I have a method to reOrder an existing HashMap by date. The HashMap is of a type <String, Object> where the Object contains a field called expPayDate and the key string is a sequential number turned into a string.. So I need to loop through the items in the sourceMap and find the item with the newest date then copy it to a tempMap in the correct order. My issue is what is the best way to determine the item with the newest date.
Your best bet will be to use a SortedMap with the Comparator interface.
Here is an example:
public SortedMap<String, Object> getSortedMap(Map<String, Object> originalMap) {
SortedMap<String, Object> tmpMap = new TreeMap<String, Object>(new Comparator<String>(){
#Override
public int compare(String key1, String key2) {
//logic for comparing dates
}
});
tmpMap.putAll(originalMap);
return tmpMap;
}
Use a TreeMap instead of HashMap. it will be sorted automatically on insertion.
Map< Date, Object> m = new TreeMap< Date, Object>();
Alternatively, if you have an existing HashMap and want to create a TreeMap based on it, pass it to the constructor:
Map< Date, Object> sortedMap = new TreeMap< Date, Object>(m);
Hope it will help you.
For simplicity I am assuming that type of your map is something more like Map<String, MyClass> map where MyClass has method like getDate() which returns expPayDate.
My issue is what is the best way to determine the item with the newest date.
If you want to find single map entry which value contains max date you don't need to sort entire map which at best would give you O(n*logn). What you need is simple iteration of all elements in map and comparing them with current max, which will be O(n) operation.
You can use stream() (functionality added in Java 8) and its max method. This method needs Comparator and you can easily create one by using comparing method and passing lambda expression which will return value which should be used when comparing.
So your code can look like
//import java.util.Map.Entry;
Optional<Entry<String, MyClass>> max = map.entrySet().stream()
.max(Comparator.comparing(e -> e.getValue().getDate()));
Entry<String, MyClass> entry = max.get();
MyClass maxMC = entry.getValue();
If you can't use Java 8 you can write your own method which will iterate over elements and find max. Such method can look like
public static <T> T max(Iterable<T> iterable, Comparator<T> comp) {
Iterator<T> it = iterable.iterator();
T max = null;
if (it.hasNext()) {
max = it.next();
}
while (it.hasNext()) {
T tmp = it.next();
if (comp.compare(max, tmp) < 0)
max = tmp;
}
return max;
}
and you can use it like
Comparator<Entry<String, MyClass>> myComparator = new Comparator<Entry<String, MyClass>>() {
#Override
public int compare(Entry<String, MyClass> o1, Entry<String, MyClass> o2) {
return o1.getValue().getDate().compareTo(o2.getValue().getDate());
}
};
Entry<String, MyClass> maxEntry = max(map.entrySet(), myComparator);
MyClass max = maxEntry.getValue();
Get all Entries by calling entrySet() method of Map
Create a custom Comparator to sort entries based upon values
Convert Entry set to List
Sort Entry list by using Collections.sort() method by passing your value comparator
Create a LinkedHashMap by adding entries in sorted order.
Look at example code # Sort HasMap by value
If you just need the minimum or maximum date, a simple for each loop might be sufficient:
Date maxDate = null;
for (Entry<String, Object> item: hashMap.entrySet())
if (maxDate == null || maxDate before((Date)item.getValue()))
maxDate = (Date)item.getValue();
This way complexity is only O(n) and insert and delete operations are cheaper than using a sortedMap. Anyway, I think patstuart's suggestion (using a sortedMap) is more elegant.
The correct solution depends on your performance constraints.
If your issue is just finding the item with the newest date, then if O(n) performance is OK you can do a scan of the values() in your HashMap and find the minimum that way.
It depends on how often you need to do this relative to other access on the data structure. It would be perfectly reasonable to use a SortedMap or use a secondary data structure such as a PriorityQueue (acting as a heap on the date), depending on your access patterns for this data structure.

Is there any data structure that offers fast key/value access, but that is also ordered and can be accessed by a position index?

Basically, I need something like a TreeMap but that would allow me to get the element at the position X efficiently.
You can use a ListOrderedMap from Apache Commons Collections.
It gives you a get(int index) method to retrieve the key at position index on top of the usual Map methods.
A balanced tree can be used for both lookups by key and by index, both in O(log N) time, if you store a "size" field in each node which tracks how many key/value pairs are contained in the node and all its descendants.
The code for looking up a value by index would look something like this (in pseudocode):
def at(index)
if index == this.left.size
return this.value
else if index < this.left.size
return this.left.at(index)
else
return this.right.at(index - this.left.size - 1)
TreeMap get complexity is O(log n)
I guess it is not a concern in performance.
Also as i know array has O(1) but the your demands match with treemap.
The SortedMap Interface with TreeMap is suitable for you :).
It wouldn't be difficult to combine some data structures to provide this. Assuming there are no duplicates then the sketch below could work. If you do need to support duplicates then wrap your objects with something that provides unique hashes like the default Object class does.
I have no idea how you want use the positional data so I didn't add any methods that relate to reordering or iterating but it wouldn't be difficult. Sounds like the Apaches ListOrderedMap is a good choice too.
public class OrderedMap<K, V>{
private ArrayList<V> values;
private HashMap<K, V> map;
private HashMap<K, Integer> keysToIndices;
public OrderedMap(){
values = new ArrayList<>();
map = new HashMap<>();
keysToIndices = new HashMap<>();
}
public void put(K key, V value){
values.add(value);
map.put(key, value);
keysToIndices.put(key, values.size()-1);
}
public T get(K key){
return map.get(key);
}
public V remove(K key){
map.remove(key);
return values.remove(keysToIndices.remove(key))
}
}

Most convenient way to get the last key or value in a LinkedHashMap?

LinkedHashMap description says "it maintains a doubly-linked list running through all of its entries" so I'm wondering how to get the last entry or key entered? Can I confidently downcast .values() to LinkedList to get that doubly-linked list and use .getLast() of that? Or is it an instance of some other Java collection?
I want to stick with java.util if possible.
Yes, you can get the last element. But you'll have to look at the suggestions from others to get the last element of the Collection<V> returned by values().
I checked in the source code that the returned values are indeed in the expected order:
The AbstactCollection<V> returned by LinkedListMap.values() is backed by an Iterator<V> over the values which is itself directly linked to the Iterator<K> over the keys. And obviously the Iterator<K> over the keys is implemented with the ordered doubly linked list.
No, sorry, you cannot.
The "maintained doubly-linked list" is not any java.util.LinkedList type or other collection. It's manually implemented in LinkedHashMap and LinkedHashMap.Entry classes.
You can only build LinkedList from values() and then use letLast() :
Foo last = new LinkedList<Foo>(myLinkedHashMap.values()).getLast();
Update: My previous answer was wrong. You cannot do it without modifying the default behaviour! See below why.
..how to get the last entry or key entered?
From the API description of LinkedHashMap you can read:
A structural modification is any operation that adds or deletes one or more mappings or, in the case of access-ordered linked hash maps, affects iteration order. In insertion-ordered linked hash maps, merely changing the value associated with a key that is already contained in the map is not a structural modification. In access-ordered linked hash maps, merely querying the map with get is a structural modification.
So what does it all mean?
access-ordered - every time you do a put or a get the order of the elements changes
insertion-ordered - when inserting elements (for the first time) they are added last
For example:
map.put(1, 1);
map.put(2, 2);
map.put(1, 10);
System.out.println(map);
... will print {1=10, 2=2} with insertion-ordered and {2=2, 1=10} with *access-ordered'. The trouble is using access-ordered if of course if you do a get operations the order also changes.
How to fix
So... how to fix. Well the LinkedHashMap cannot be used directly used. So you can wrap it (do not care about the corny name) and override the put and the putAll methods so that they remove the key from the map first before putting it back in!
class BestLinkedHashMap<K, V> extends LinkedHashMap<K, V> {
#Override
public V put(K key, V value) {
V last = super.remove(key);
super.put(key, value);
return last;
}
#Override
public void putAll(Map<? extends K, ? extends V> m) {
for (K key : m.keySet())
super.remove(key);
super.putAll(m);
}
}
Then to get the last element, either do:
wrap the output from in a LinkedList implementation:
V v = new LinkedList<V>(map.values()).getLast();
toArray() way:
Collection<V> values = map.values();
V v = values.toArray(new V[0])[values.size() - 1];
iterate to the last element using the iterator:
Iterator<V> it = values.iterator();
V last = null;
while (it.hasNext())
last = it.next();
I have "extended" the Jdk LinkedHashMap to allow that, you can take a look at: LinkedHashMapEx.java

Implementation of sorting in Vector

I have a Collection as
Vector<HashMap<String, String>>
Actually I am using this as list items of list view in android.I used SortedMap but I did not get correct result. I think this is because HashMap's structure is
hashMap.add("Name","value_of_name");
hashMap.add("Counts","value_of_counts");
Now I am adding it to Vector.
I want to sort vector's element by Name key of hashMap.
I know about Collection.sort and I can sort this using ArrayList and POJO class. But I do not know how to use it with adapter of my ListView
How can I sort elements. And is there any better solution (Regarding my data-structure of collection, which can be use with adapter easily) ?
You need to a implement a Comparator<HashMap<String,String> > and place the logic of your sort ordering inside its compare method.
Not sure I understand correctly. This will sort the vector on one key of the maps.
Collections.sort(yourVector, new Comparator<HashMap<String,String>>() {
public int compare(HashMap<String,String> a, HashMap<String,String> b) {
return a.get(yourKey).compareTo(b.get(yourKey));
}
});
Have you never thought about taking a look at collections in java.util package ?
You would then have discovered that Treemap already implements balanced tree sorting for Comparable items, like String is.
So, to have your items sorted, just repalce your HashMap with a TreeMap, and all the work will be done.
BTW what does this vector does here ? They're sooo Java 1.1 (fifteen years old, in other words)
If you want to sort the maps in the array, use a SortedMap implementation like TreeMap or ConcurrentSkipListMap. This takes a vector of HashMaps and returns a ArrayList (a non-synchronized and faster collection than Vector) of SortedMaps.
public ArrayList<SortedMap<String, String>> sortMaps(Vector<HashMap<String, String> maps) {
ArrayList<TreeMap<String, String>> returnMaps = new ArrayList<TreeMap<String, String>>();
for(HashMap<String, String> theMap : maps) {
// TreeMap is a sorted map and this will use the default String.compareTo
TreeMap<String, String> newMap = new TreeMap<String, String>();
// put all the items from the HashMap into the TreeMap, which will autosort
newMap.putAll(theMap);
returnMaps.add(newMap);
}
return returnMaps;
}
To sort the Vector by the first keys (lowest keys, first alphabetically) of the hash map try the following before the return line:
// this sorts the vector by first keys
Collections.sort(returnMaps, new Comparator<SortedMap<String,String>>() {
public int compare(SortedMap<String,String> a, HashMap<String,String> b) {
return a.firstKey().compareTo(b.firstKey());
}
});
Or if you want to sort by last key (highest keys, last alphabetically):
// this sorts the vector by first keys
Collections.sort(returnMaps, new Comparator<SortedMap<String,String>>() {
public int compare(SortedMap<String,String> a, HashMap<String,String> b) {
return a.lastKey().compareTo(b.lastKey());
}
});
To return one sorted map of all keys (will stomp on any duplicates):
public SortedMap<String, String> singledSortedMap(Vector<HashMap<String, String> maps) {
// this will end up with all the values, sorted by natural string ordering
SortedMap<String, String> returnMap = new TreeMap<String, String>();
for(HashMap<String, String> theMap : maps) {
returnMap.putAll(theMap);
}
return returnMap;
}
The best (fastest) way it to use a TreeMap instead. If you supply it with the correct Comperator all the items in the TreeMap will be sorted.
The important question: Why do you have a Vector of HashMaps?

Categories

Resources