Multiple Indexes for a Map VS Complex Key - java

I want an indexed collection in Java, but my final Object needs to be indexed by many keys.
I have now a collection of this kind:
Map<String, Map<String, Map<String, Map<String, Map<String, Object>>>>> objects
I am asking if this is efficent or it is better to build a more complex key Type to include all of the 5 string keys.
PS:
Sorry i didn't explain the whole thing.
When i try to get an object with this collection the path to this object might be: (call AX the generic key in 1-st position, BX the generic key in 2-th position, etc...)
A1 -> B1 -> C1 -> D1 -> E1. But it can be also A1 -> B2 -> C1 -> D1 -> E1.
So i am asking if a complex key that overrides equals to match B2 and B1 as one and match the two described paths it's more efficent than have a nested Map.

If you don’t need a tree structure and you always want to find one stored object. I would suggest to have a compound key. You can concatenate Strings with delimiter as a key.
For two dimensions Table from Guava can be used: https://github.com/google/guava/wiki/NewCollectionTypesExplained#table

It depends on what you need it for. Will you only access the most nested objects, one at the time, or some of the outer maps as well. As an example: Lets assume that objects are houses and the map keys are different parts of the address. First one is country, then city, then street, then house number.
If you want to be able to get all houses in city X you problably want to use nested maps like in your example. With complex Address class as a key it won't be really possible.
If you don't need that functionality and you will always use all parts then a composite class will be more convenient
Edit:
After your edit it seems that a composite class will be a better option. Calling a constructor with meaningful parameter names (as some IDEs show those) will be much nicer than chaining 5 times .get(String).

Related

Is it "nice" in java to use map which has maps as values?

For example, is it generally good to have a structure like :
Map <Object, Map>
In my case, at first sight I do need some kind of structure that would have for example mapping String -> Map<...>,
or it is weird and I should solve the problem somehow else?
It has a few code smells for me.
The inner Map does not specify the generic types.
It says you need to do two look ups. I would prefer a composite key and a single lookup on a flattened map.
Adding to this structure must be overly complicated.
The key is object, not strongly typed.
So I would prefer to see:
Map<CompositeKey, ValueType>
Where CompositeKey is a class with correct equality implementation made up of the first and second keys. and ValueType is not a Map.
So for example, instead of nested maps:
A -> { 1 -> "ABC",
2 -> "DEF"},
B -> { 1 -> "abc",
3 -> "def"}
You have a flat map and a composite key:
(A,1) -> "ABC",
(A,2) -> "DEF",
(B,1) -> "abc",
(B,3) -> "def",
It is not inherently good to design your data structure this way. It also is not necessarily bad.
If you will be doing lookup on the map object I would consider using a HashMap to improve the execution time.
From #Rafael Osipov, In cases involving concurrency consider using ConcurrentHashMap, for data integrity.
There's nothing at all wrong with having a map as the value in a map. It's a fairly common way of implementing fast lookup using multiple keys.
For example, you are storing a large number of Student records:
class Student
private String name;
private int age;
private School school;
}
You could store these in a List<Student> but if you want to find, say, all students at a certain school who are 16 years old it might be better to be able to say:
Map<School,Map<Integer,List<Student>>> index;
List<Student> subset = index.get(School.STATE_HIGH).get(16);
Note that there are other ways of doing the same thing such as having a separate composite key type (in my example above, representing school and age together). Also keep in mind that if your primary purpose in using a map is efficiency then, in many cases, you are probably optimising prematurely. Unless the map is storing many millions of values or you are going to be accessing them many thousands of times a second then you might want to consider a simple list that you search through.

What would be the best suited data structure to represent the following scenario

I have a matrix-like data structure that I want to preserve in its original form as much as maybe allowed in a language such as Java. It is as follows:
a() b() ... n()
a() .1 .2 ... .9
b() .4 .3 ... .6
..
.
n() .1 .7 ... .4
One could imagine a(), b(), ... n() as instances of an object. The only reason why I have the parenthesis here is because I'm using a domain-specific language to solve the problem. But, I could very well raise this question for mainstream languages such as Java. How would I design a data structure, (or use an offered type) and subsequently an easy function call, where I could pass in two object parameters (i.e. (a,b) ) and get back the numeric value. The constraint is to not to resort to define a complicated class defining a series of sub hashmap fields and so on and so forth to store the data one row or column a time. Does Java provide a built in type to offer this as a direct solution?
You can use a Map in Java with the key as a object combining the two objects (like a pair).
Java does not provide a implementation of tuples/pair. But you can use Apache Commons or implement your own. Take a look to this question also.
A Map can only hold a key-value pair. A Table from Google Guava can hold row, column and value information.
You would instantiate one like so:
Table<Double, String, Double> table = HashBasedTable.create();
...and you can use whatever row, column, value triplet you like. The above is just a for-instance.
You can use an adjacency matrix graph or even a two dimensional array, I believe both are valid solutions to your problem.

How to encapsulate a Map into a custom object

My coworker tells me that it's lazy to use Maps, and that oftentimes the programmer's purpose would be better served by an actual object. But I don't know the best way to do so. This is further complicated (to me) by the fact that the key is an Enum type.
Say I have a Hashmap<MyEnum, MyObj> which is expected to have four hashmap keys (one for each value in MyEnum). The MyObj hashmap value is the latest of several MyObjs in a database which have the given enum value.
My best guess involves an object with four fields, or maybe two arrays containing the keys and values in order.
Not sure if this is clear or not (It's 5PM on Thursday = I'm brain-dead), so please ask for clarification if necessary.
While there's nothing wrong with using Maps for their intended purpose, Maps are sometimes misused as substitutes for strongly-typed objects.
String firstname = (String)myMap.get("first_name");
... as opposed to:
String firstName = person.getFirstName();
Since Java implements enums as classes, you might want to consider putting the value you're looking for onto your enum class directly:
MyEnum val = getVal();
MyObj obj = val.getMostRecentMyObj();
But I'd pay attention to separation of concerns to determine whether this really makes sense. It could well be that a Map is the appropriate tool for this job.

What is the use of Pair Class and why have the implemented here?

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...

Key in HashMap java

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...

Categories

Resources