I have an Android app in which I use a HashMap to store container objects. During the course of the App, the datastructure is accessed continuously.
However, about half the time, the reference used in not the Key in the map but another variable from the object so I end up looping over the structure again and again.
Is there an efficient way to have a datastructure indexed on two keys in Java ?
Why not two maps with different keys, but that both refer to the same values?
Manage two maps, where two sets of keys map to the same underlying set of objects. Wrap them in a class that has methods similar to a normal map, but internally searches on both keys, and synchronizes additions and deletions.
This is efficient because manipulations are (in the worst case) linearly proportionate to managing a single map.
I'd create a key object that combines the two variables.
You could use one map with both keys:
Map<Object, Person> personMap = new HashMap<Object, Person>()
Person person = ...
personMap.put(person.getName(), person)
personMap.put(person.getSSN(), person)
Then you can retrieve by the key. This of course assumes that there are no collisions in your key usage. If your two keys are different class types, then this is safe to do. If your keys are the same type (example String), then you may not want to use the two maps solution.
Follow-up: This approach does suffer from losing type safety, but it only impacts put(K, V) and putAll(Map<? extends K, ? extends V>), as get(Object) and containsKey(Object) always accepts Object.
So with this limitation I'd wrap this single map or go with the two map solution (also wrapped).
Related
What is the difference between a Pair Class and a HashMap. I see both of them having key and value.
Code Earlier:
List<Patient> patientDetails = new ArrayList<Patient>();
Patient patientInfo = new Patient();
patientInfo.setReligion(Constants.ReligionArray[custom.getReligion()]);
patientDetails.add(patientInfo);
The code has been changed to this today.
Changed Code
List<Pair<String, String>> patientInfo = new ArrayList<Pair<String, String>>();
patientInfo.add(new Pair<String, String>("Religion", Constants.ReligionArray[custom.getReligion()]));
Why have they implemented a Pair Class here? What could be the reason.
What is the difference between a Pair Class and a HashMap.
Note: Both the code works perfectly.
I think that the question you're asking is: what is the difference between
List<Pair<T,S>> and HashMap<T,S>. There are many.
In general, a Map object is used to associate a value with a key and provide means to quickly get the values based on the key. There can usually be a single value associated with one key.
A List is an ordered container in which objects are stored, provides means to iterate over its contents and get an element based on it's location in list (get Nth element). Usually the same elements may be duplicated within a list.
In your case, when you are using a list, your patients can have a several religions. To find what kind of religion your patient has, you have to manually search the list for the pair with the first element set to religion.
Had you used a map, each patient would have a single religion associated with him (or none). You could also find the religion quickly through Map<String,String>.get(String key)
Actually, your code has been changed away from typical Java approach into what is most often referred to as "object denial". The replacement that happened is from a dedicated domain object Patient into a generic Pair<String, String>.
So you are asking about the difference between List<Pair<String,String>> and a Map<String,String>. The former contains more information because it maintains the insertion order of the individual pairs and also allows random access based on position in the list.
A Map, on the other hand, allows efficient lookup based on the key, which is what is really needed.
The Pair class is just a structure with two fields, that doesn't have a special name (unlike Person). Pairs (and more generally, tuples) are often used in languages like Python when you don't want to give a name to some intermediate structure. In your case, instead of (possibly) under-defined Person object you have a simple fully-defined object. Perhaps, the usage of Pair is questionable in Java, beacause of a rather clumsy syntax (compare to Python, where the pair would be just ("Religion", religions)).
You can think of Map as a collection of pairs with the unique constraint on the first element.
Before I talk about the difference between a Pair and a HashMap, let me tell you why that's not really the question you want answered. What you really want to know is why would you take an Object and break it into a list of key/value primitivies.
The code you are referencing is converting from an object oriented approach of using a class Patient (which really looks like it should be called PatientInfo) into a list of primitives, they are essentialy "deObjectOrienting" the class.
So in their model each class variable becomes a Pair where the variable name become the key, and the variable value become the value.
Here is an expanded example class
// Old style (Object oriented)
class PatientInfo{
String religion;
String address;
}
PatientInfo patientInfo = new PatientInfo();
patientInfo.setReligion("myReligionName");
patientInfo.setAddress("address of the patient");
// New Style, key/value primitive pairs (very not object oriented)
Pair<String,String> religionInfo = new Pair<String,String>("religion","myReligionName");
Pair<String,String> addressInfo = new Pair<String,String>("address","address of the patient");
They then add these either the Patient or the Pair into a List.
Why would someone do this is a good question. Most people try to become more object oriented as it makes coding easier. Perhaps since it's only a single variable in the Clss they figured why not remove the class entirely?
To your original question between a Pair and a HashMap. A Pair is just a key/value. A HashMap is the collection usually used to store many key/value pairs. Here they are using a List where they should probably be using the HashMap.
The Pair class can be compared to the Map.Entry of a HashMap. A HashMap may contain multiple key/value pairs stored and looked up efficiently by the key.
A List of Pairs cannot be looked up by the key without iterating inefficiently (depending on the size), but it can be referenced by index. There is also nothing enforcing one and only one key in the list.
A Pair object stores exactly one key and one value. A HashMap is a structure where you can store several key/value pairs.
A "pair" is a pair of items that you want to be related in some way or another. There is no key enforcement, lists of items or anything else. It is simply a shortcut for when you have a pair of items that are really most useful as a pair of items, but simple enough structure where there is no need to create a separate class to relate them. Examples: points on a rectangle, ip addresses to domains, etc.
A hashmap can be thought of as a mapping of pairs, with an enforcement of a "key" specification. In this case the first item of the pair becomes "constant" and is used to refer to the second item. In my example of pairs I used ip addresses to domains. In this case we would use the domain as the "key" and use it to refer to the ip address of the machine. This IP adress could of course change, but the domain would always be the same, and is used to quickly look up the currently associated ip address. Note, that the restriction of the first item in the pair being the "key" come from the hash map, and not the specification of pair istelf. The hash part of hashmap then refers to how items are looked up, in this case a hash table, on the 'first' item in the pair...
As we know that, SortedMap maintains the entries as sorted by keys. I read many threads in this forum and saw lots of example which sorts the SortedMap, by values. However, as you know when I put an item to default SortedMap it does not sort the Map again just put this new entry where it is supposed to be.
For example,
SortedMap<String,Person> sortedMap = new TreeMap();
Person p1 = new Person("John",38);
sortedMap.put(p1.getName(), p1);
Person p2 = new Person("Tom",34);
sortedMap.put(p2.getName(), p2); // does not sort, maintains sorted set by comparing the other values
Person p3 = new Person("Susan",21);
sortedMap.put(p3.getName(), p3); // does not sort, maintains sorted set by comparing the other values
In many threads in this forum, I saw many many code that sorts the SortedMap by values by calling a sort method like:
sortedMap.sort(sortedMap.entries());
This or something else method is being called to get values as sorted.
But, I need to a Map implementation which keeps the values as sorted without a calling sort method as I explained in above. For example, in above code I just can call the firstKey() method; but instead I need to call a firstValue() method.
Person minimumAgePerson = sortedMap.firstValue().
System.out.println(minimumAgePerson.getName()); // it should print "Susan"
SortedSet is not appropriate for my requiremenets because I can put some new Objects ( Person ) whose key values already in the map, these just added entries should override the existing objects ( so I need a map ):
Person p4 = new Person("Susan",39);
sortedMap.put(p4.getName(),p4);
Person newMinimumAgePerson = sortedMap.firstValue();
System.out.println(newMinimumAgePerson.getName()); // it should print "Tom"
Is there an implementation to accomplish this taks or do I need to implement SortedSet myself?
Often, the simplest and safest way of dealing with this type of problem is to write a class that uses two different standard collections. The class can offer exactly the methods you need, not necessarily conforming to any of the java.util interfaces.
Given the stated requirements, I would use a SortedMap to contain the values, combined with a HashMap mapping keys to values. To prevent duplicate keys, put the key-value pair in the HashMap, checking the put result. If the key was already present, remove the old value from the SortedMap before adding the new value.
If you have additional requirements, this particular design may not cover everything, but the concept of combining java.util structures is a generally useful one.
I think the best way for you is to create a custom type containing both a Map (for the key association), and a SortedSet (in order to sort values)
It is not clear to me if you want to be able to have the same value for two different keys. In this case, you'd need to use some kind of SortedMultiSet.
There is no implementation that contains a sort by both Key and Value. But really any implementation that did do this would need a separate datastructure for the sorting by value anyway, so you might as well create that datastructure yourself.
I would suggest either just implementing a sorted structure, using an existing one Like TreeMap or a PriorityQueue depending on your needs. Once that was done I would probably extend TreeMap with a custom structure and override the put,remove,addAll, etc methods to place it both in the super map, and also in your sort by keys structure.
I want to find something like ImmutableLinkedHashMap<> in Guava library.
I need to use an immutable key-value data structure with an insertion order.
So, what should I use?
I am not sure I am understanding exactly what you are after, but if it is a really immutable Map, you mght want to look at ImmutableMap
As mentioned in the doc:
An immutable, hash-based Map with reliable user-specified iteration order. Does not permit null keys or values.
Unlike Collections.unmodifiableMap(java.util.Map<? extends K, ? extends V>), which is a view of a separate map which can still change, an instance of ImmutableMap contains its own data and will never change. ImmutableMap is convenient for public static final maps ("constant maps") and also lets you easily make a "defensive copy" of a map provided to your class by a caller
E.g, you could use it in a similar fashion:
Map<Integer, String> m = ImmutableMap.of(5,"Five",6,"Six",7,"Seven");
Hope this is what you were after.
First create a LinkedHashMap and then use ImmutableMap.copyOf(linkedHashMap) to create an immutable copy which will have the same ordering as the original map.
I usually come across scenarios while using HashMap in Java as follows :
I've a list of Objects of class A (List<A>)
A has fields int f1, int f2 and other fields.
I've to construct a map from List to perform O(1) lookup for the Objects of A. The key is combination of f1 and f2 (both being integers).
Now which of the following would be the best practice to use for the map
case 1 : in general
case 2 : f2 can take only 2 to 3 different values, while f1 can take large number of values.
Map<Integer, Map<Integer, List<A>>> // construction of map is cumbersome
Map<String, List<A>> //(key : String f1 + "_" + f2)
Map<Integer, List<A>> //(I tend to use this for case 2)
Missed to clarify one thing here. f1 and f2 don't uniquely identify objects of A. Corrected the map definitions.
If those two fields tend to be immutable (they don't change once set), you can override the equals() and hashCode() methods of A, and simply store a:
Set<A> //(key: fields f1 and f2, via hashCode() method)
If they are not immutable, you cannot use them for the key anyway, since they might change.
I think Map is suitable for case 1, and for case, i recommend List, and this list only have 2-3 elements, then you can map an index to the specific field value.
Why use a map at all? If you don't really need Key-Value pairs, you can just use a HashSet<A>. The lookup is still O(1) and you don't have to bother getting a value from the key.
Of course, the HashSet is probably just a HashMap with null values, but you don't have to invent keys and values.
I don't like using Strings as composite keys. Some blogger out there put it well: Strings are good for things that are text, and not good for things that aren't text.
Why not just create a simple IntPair class with two int fields, and appropriate hashCode() and equals(Object) overrides? It'll take you two seconds in an IDE (not much longer without one), and you'll have a more specific, semantically meaningful key type.
Key is unique in HashMap...because internally in java key is set as
final Key
int static Entry class in java
That's why the key is unique it won't allow duplicates...
I'm looking for a way to maintain the sorting on my key-value pairs. They are sorted by variables outside of the actual key-value pairs (for better UI). I am currently using a Hashtable, but that does not maintain the sorting =(
Hashtable<Integer, String> subscriptions = getUsersSubscriptions(user);
Is there some simple way that Java lets one store pairs? The best idea I can think of is using 2 associated ArrayLists (one of type Integer, another of type String). Can someone think of something better?
If your key-value pairs are already sorted, LinkedHashMap will maintain order of insertion.
In other words, the keys returned by map.keySet() will be in the exact order you put them into the map.
SortedMap<Integer, String> myMap = new TreeMap<Integer,String>();
If you have a custom sorting, pass a Comparator instance to the constructor of the TreeMap. But be careful doing so, as using a Comparator that does not go well with natural Integer order would make things impossible to understand and debug.
LinkedHashMap can be used here.
Is there some simple way that Java lets one store pairs?
Create a custom class that stores the two properties.
They are sorted by variables outside of the actual key-value pairs
Add a third property for the sort data.
Then your class can implement Comparable to sort the data as required based on this property.
Or you can use a custom Comparator to sort on the sort data field.
Now the class instances can be stored in an ArrayList.