Java class design to support multi-valued options - java

The following are some of the codes:
ENJOY08A,
AUTO09B,
PLAY06D,
SUMMER08W,
WINTER03S,
LEAF02A,
Each of these values correspond to a specific area.
For example, ENJOY08A and AUTO09B correspond to DEPT_A
PLAY06D corresponds to DEPT_B
SUMMER08W, WINTER03S and LEAF02A corresponds to DEPT_C
There are a fixed number of areas (5 areas), but unlimited codes. A code will correspond to only one area, but an area can have any number of codes.
None of the above will be stored in the database.
I need to create a Java class which will support the following operations..
Given the code, I need to know the corresponding area.
Given the area, I need to know all the corresponding codes.
What's the best way to go about designing the Java class?

Check out the guava multimap. I believe it provides the functionality you want.

I think the simplest method is to put the AREAS into a <String, Set> HashMap, then enter all the associated CODES into the relevant map. Then, you can get the Set of all codes for an area or iterate over the sets to find which one contains the code you are searching for.
for (String k : (Set<String>)areas.keySet()) {
if (areas.get(k).contains(theCode))
return k;
}
return "NO CORRESPONDING AREA FOUND";

Use a MultiMap (Google guava library), which is a bi-directional map, as a backend.
Fill the map using normal puts, either during construction time or from a properties file using the Java Properties class
Offer two interface methods: regionForCode(String code) and codeForRegion(String region) which use the BiMap to retrieve the mapped values.
You might even consider putting region into an enum instead of a simple String, because your region values are fixed. Then the domain would be described a little bit more consistently.
Edited: I noticed that BiMap is for unique mappings. The anser with MultiMap is correct, so I corrected my answer.

Since the number of codes is unlimited, you need to come up with a rule for mapping codes into departments. Probably it will be something like add up all the codes and take that sum modulo 5. There are an infinite number of choices for what this rule can be.
Something like
public class DepartmentCoder {
public static String toCode(Department department) {
// TODO: Randomly generate a string having the desired property, such
// as the sum of the string's codepoint modulo the number of departments
// equaling the ordinal value of the department.
}
public static Department(String code) {
// TODO: Do some math on the codepoints of the string
return result % Deparatments.NUMBER_OF_DEPARTMENTS;
}
}
I think, though, that the notion of "code" (as opposed to compression or encryption) is that the code values are fixed. Any rule-based solution can be figured out more easily.

I would use a class with two Maps.
The first is a Map<String, Set<String>> for looking up the set (alternatively List) of codes for a given area. Somebody also suggested Guava's MultiMap, that is essentially what this is.
The second would be a Map<String, String> for looking up the area of any given code.
Then just implement the appropriate String findAreaForCode(String code) and Set<String> listCodesInArea(String area) methods.
Finally, if the list of areas is small, finite and relatively static (doesn't need to grow dynamically at run-time) then I would consider using a Java enum in place of an ordinary String.

Related

What is the benefit of using a custom class over a map? [duplicate]

This question already has answers here:
Class Object vs Hashmap
(3 answers)
Closed 3 years ago.
I have some piece of code that returns a min and max values from some input that it takes. I need to know what are the benefits of using a custom class that has a minimum and maximum field over using a map that has these two values?
//this is the class that holds the min and max values
public class MaxAndMinValues {
private double minimum;
private double maximum;
//rest of the class code omitted
}
//this is the map that holds the min and max values
Map<String, Double> minAndMaxValuesMap
The most apparent answer would be Object Oriented Programming aspects like the possibility to data with functionality, and the possibility to derive that class.
But let's for the moment assume, that is not a major factor, and your example is so simplistic, that I wouldn't use a Map either. What I would use is the Pair class from Apache Commons: https://commons.apache.org/proper/commons-lang/javadocs/api-3.1/org/apache/commons/lang3/tuple/Pair.html
(ImmutablePair):
https://commons.apache.org/proper/commons-lang/javadocs/api-3.1/org/apache/commons/lang3/tuple/ImmutablePair.html
The Pair class is generic, and has two generic types, one for each field. You can basically define a Pair of something, and get type safety, IDE support, autocompletion, and the big benefit of knowing what is inside. Also a Pair features stuff that a Map can not. For example, a Pair is potentially Comparable. See also ImmutablePair, if you want to use it as key in another Map.
public Pair<Double, Double> foo(...) {
// ...
Pair<Double, Double> range = Pair.of(minimum, maximum);
return range;
}
The big advantage of this class is, that the type you return exposes the contained types. So if you need to, you could return different types from a single method execution (without using a map or complicated inner class).
e.g. Pair<String, Double> or Pair<String, List<Double>>...
In simple situation, you just need to store min and max value from user input, your custom class will be ok than using Map, the reason is: in Java, a Map object can be a HashMap, LinkedHashMap or and TreeMap. it get you a short time to bring your data into its structure and also when you get value from the object. So in simple case, as you just described, just need to use your custom class, morever, you can write some method in your class to process user input, what the Map could not process for you.
I would say to look from perspective of the usage of a programming language. Let it be any language, there will be multiple ways to achieve the result (easy/bad/complicated/performing ...). Considering an Object oriented language like java, this question points more on to the design side of your solution.
Think of accessibility.
The values in a Map is kind of public that , you can modify the contents as you like from any part of the code. If you had a condition that the min and max should be in the range [-100 ,100] & if some part of your code inserts a 200 into map - you have a bug. Ok we can cover it up with a validation , but how many instances of validations would you write? But an Object ? there is always the encapsulation possibilities.
Think of re-use
. If you had the same requirement in another place of code, you have to rewrite the map logic again(probably with all validations?) Doesn't look good right?
Think of extensibility
. If you wanted one more data like median or average -either you have to dirty the map with bad keys or create a new map. But a object is always easy to extend.
So it all relates to the design. If you think its a one time usage probably a map will do ( not a standard design any way. A map must contain one kind of data technically and functionally)
Last but not least, think of the code readability and cognitive complexity. it will be always better with objects with relevant responsibilities than unclear generic storage.
Hope I made some sense!
The benefit is simple : make your code clearer and more robust.
The MaxAndMinValues name and its class definition (two fields) conveys a min and a max value but overall it makes sure that will accept only these two things and its class API is self explanatory to know how to store/get values from it.
While Map<String, Double> minAndMaxValuesMap conveys also the idea that a min and a max value are stored in but it has also multiple drawbacks in terms of design :
we don't know how to retrieve values without looking how these were added.
About it, how to name the keys we we add entries in the map ? String type for key is too broad. For example "MIN", "min", "Minimum" will be accepted. An enum would solve this issue but not all.
we cannot ensure that the two values (min and max) were added in (while an arg constructor can do that)
we can add any other value in the map since that is a Map and not a fixed structure in terms of data.
Beyond the idea of a clearer code in general, I would add that if MaxAndMinValues was used only as a implementation detail inside a specific method or in a lambda, using a Map or even an array {15F, 20F} would be acceptable. But if these data are manipulated through methods, you have to do their meaning the clearest possible.
We used custom class over Hashmap to sort Map based on values part

Java Map of Map

I need to do a look-up table based on two keys. I am building a mileage look-up chart similar to what is seen in the back of road maps. A sample of a chart can be found here. If you know the starting city is x and the ending city is y you look to find the intersection to find out the total miles.
When I first started attacking this problem I though of doing Two maps. City being an ENUM of my city of interest.
Map<City, Map<City, Integer>> map;
But, as I researched I am seeing warnings about Map's that have values of type Map. Is there an easier solution to my problem that I might be overlooking? With this being 66x66 col*row I want to make sure I do it right the first time and dont have to redo the data entry.
As a note I will be saving all my values into a database for easy update and retrieval so the solution would need to be easy to map with JPA or Hibernate etc.
Thanks in advanced.
It'd be easier if you do this:
Map<Pair<City, City>, Integer> map;
That is: create a new generic class, let's call it Pair that represents a pair of cities, and use it as key to your Map. Of course, don't forget to override hashCode() and equals() in Pair. And take a look at #increment1's answer, he's right: if the distance from city A to B is the same as the distance from B to A, then there's no need to store two pairs of cities, a single pair will do, no matter the order used to add the cities to the Map.
Notice that this is the strategy used by ORMs (for instance, JPA) when mapping composite keys in a database: create a new class (Pair in the example) that encapsulates all the objects used as keys, it'll be much easier to manage this way: conceptually, there's only one key - even if internally that key is composed of several elements.
Make a map of Path's, where Path is a custom class that holds two cities. Remember to override equals and hashcode.
Edit: Why is there 66x66 paths? Is the mileage different regarding which way you go (probably is a bit difference, but do you have that data)? If not, you can discard more than half that number of entries (the half is obvious, the 'more' part is from New York to New York entry no longer needs to be saved with 0).
You should create a simple class that contains two City references, from and to, and which overrides equals and hashCode appropriately. Then use that as your key.
Similar to other answers, I suggest creating a city pair class to be your map key (thus avoid a map of maps). One difference I would make, however, would be to make the city pair class order agnostic in regards to the cities in its hashCode and equals methods.
I.e. Make CityPair(Seattle,LA) equal to CityPair(LA,Seattle).
The advantage of this is that you would then not duplicate any unnecessary entries in your map automatically.
I would achieve this by having hashCode and equals always consider city1 to be the city with the lower ordinal value (via Enum.ordinal()) in your enum.
Alternatively, try this simple unordered pair implementation given in another question and answer.
If you're using Eclipse Collections, you can use MutableObjectIntMap and Pair.
MutableObjectIntMap<Pair<City, City>> map = ObjectIntHashMap.newMap();
map.put(Tuples.pair(newYorkCity, newark), 10);
map.put(Tuples.pair(newYorkCity, orlando), 1075);
Assert.assertEquals(10, map.get(Tuples.pair(newYorkCity, newark)));
Assert.assertEquals(1075, map.get(Tuples.pair(newYorkCity, orlando)));
Pair is built into the framework so you don't have to write your own. MutableObjectIntMap is similar to a Map<Object, Integer> but optimized for memory. It's backed by an Object array and an int array and thus avoids storing Integer wrapper objects.
Note: I am a committer for Eclipse collections.
To do the same as the graphic, i would use a 2d- array.
// index is the city code:
int[][] distances;
store the city code in a
Map<String, Integer> cityNameToCodeMap
Use it as follows;
Integer posA = cityNameTCodeMap.get("New York");
// TODO check posA and posB for null, if city does not exits
Integer posB = cityNameTCodeMap.get("Los Angeles");
int distance = distances[posA][posB];
reason for this design:
The matrix is in the graphic is not a sparse matrix, it is full.
For that case an 2d-array uses least memory.
There is another way to do this, that may work for you. Basically, you want to create a class called something like CityPair. It would take 2 arguments to its constructor, the start and end cities, and would override the hashcode function to generate a unique hash based on the two inputs. These two inputs could then be used in a HashMap<CityPair,Integer> type.
if there are only 66 cities, then your hashing function could look something like this:
//first assign each city an id, 0-65 and call it city.getID()
#Override public int hashCode()
{
return ((city1.getID() << 16) | (city2.getID()))
}
of course as noted in the comments, and in other answers, you will want to override the function prototyped by:
public boolean equals(Object)
from object so that the map can recover from a hash collision

map vs ?? for storing name and score

I used hashmap to store data.
The problem is that I just noticed hashmap can't have more than one same key.
What else should I use to store data which the data looks like this:
Name1 100.0
Name2 99.8
Name3 121.5
...
Other thing I'm trying to do is to show data of one certain person, when I call that key.
So, is there way to store more than one value related to one key? or should I use other type of storage?
A hashmap can have duplicate keys if you store the values within another data structure such as a linked list or a tree at each key index. Then you just have to decide how to handle the collisions.
Edit:
HashMap
["firstKey"] => LinkedList of (3,4,5)
["secondKey"] => null
["thirdKey"] => LinkedList of (3)
To extend on Matthew Coxes answer, you could extend the Hashtable Class so that it automatically manages your lists for you and would give you the appearance of having multiple keys.
The Google guava library contain some collection type that allow for more that one element per key. The Multimap is the first one that come to mind.
http://docs.guava-libraries.googlecode.com/git-history/release/javadoc/com/google/common/collect/Multimap.html
Guava in general contain a lot of very convenient utilities, I think its worth checking out.
If you can't use an external library, you can simply (Like Matthew Cox said) mix a map and a List with Map<K, List<V>>. But that is a bit more inconvenient to work with since you have to initialise a list for every key.
I'd rather go with my own datamodel and store that in a list, or map if you want fast access, e.g.
public class Player {
private String name;
private List<Float> scores;
}
The advantages:
you can easily see, what the structure wants to express
you can easily extend it (e.g. add aliases for the player, or calculate the avarage scor of player 1)

Comparing keys of a multi-dimensional HashMap

I am working on an application with a number of custom data classes. I am taking input for my application from 2 different places and want to cross-reference between the two to help ensure the data is accurate.
I have a Map.Entry<String,HashMap<String, Integer>> object called chromosome, where each value is called a marker.
I also have a custom object called IndividualList individuals which extends HashMap<Integer,Individual> where each Individual has a method Genotype getGenotype() which returns the non-static variable genotype. Genotype extends HashMap<String,String[]>
I want to look at each the key for all my marker objects and check whether each of them are present as a key in any Individual's genotype. Every Individual has the same keys in its genotype so I only need to test for one Individual.
The problem I am facing is which Individual to test, as because it is a HashMap I cannot simply just arbitrarily choose the first element, so what I am doing at the moment is taking the values of individuals as a Collection then converting these to an ArrayList<Individual> then taking the first of these elements (which is just an arbitrary one as HashMap is unordered) to get an Individual then taking this Individual's genotype and comparing marker.getKey() with the keys in the genotype. Like so :
for(Map.Entry<String, MarkerPosition> marker : chromosome.getValue().entrySet())
if(!(new ArrayList<Individual>(individuals.values()).get(0)
.getGenotype().containsKey(marker.getKey())))
errors.add("Marker " + marker.getKey() + " is not present in genotype");
But as you can see, this is horrid and ugly and far too complicated, so I was wondering if there is a much simpler way of achieving what I want that I am missing.
Thanks!
Why can you not arbitrarily choose the first element of a HashMap?
individuals.entrySet().iterator().next()
individuals.values().iterator().next()
This will probably be the same entry each time. You should make sure the map is not empty to avoid an exception.
...This question is really confusingly phrased and difficult to understand, but I'm not clear on why you don't just use
individuals.values().iterator().next()
instead of new ArrayList<Individual>(individuals.values()).get(0).
(If you can use third-party libraries, your code would probably be significantly clearer overall if you used a Guava Table, which is a general-purpose, significantly "cleaner" replacement for a Map<K1, Map<K2, V>>. Disclosure: I contribute to Guava.)

Map with two-dimensional key in java

I want a map indexed by two keys (a map in which you put AND retrieve values using two keys) in Java. Just to be clear, I'm looking for the following behavior:
map.put(key1, key2, value);
map.get(key1, key2); // returns value
map.get(key2, key1); // returns null
map.get(key1, key1); // returns null
What's the best way to to it? More specifically, should I use:
Map<K1,Map<K2,V>>
Map<Pair<K1,K2>, V>
Other?
(where K1,K2,V are the types of first key, second key and value respectively)
You should use Map<Pair<K1,K2>, V>
It will only contain one map,
instead of N+1 maps
Key construction
will be obvious (creation of the
Pair)
Nobody will get confused as to
the meaning of the Map as its
programmer facing API won't have changed.
Dwell time in the data structure would be shorter, which is good if you find you need to synchronize it later.
If you're willing to bring in a new library (which I recommend), take a look at Table in Guava. This essentially does exactly what you're looking for, also possibly adding some functionality where you may want all of the entries that match one of your two keys.
interface Table<R,C,V>
A collection that associates an
ordered pair of keys, called a row key
and a column key, with a single value.
A table may be sparse, with only a
small fraction of row key / column key
pairs possessing a corresponding
value.
I'd recommend going for the second option
Map<Pair<K1,K2>,V>
The first one will generate more overload when retrieving data, and even more when inserting/removing data from the Map. Every time that you put a new Value V, you'll need to check if the Map for K1 exists, if not create it and put it inside the main Map, and then put the value with K2.
If you want to have an interface as you're exposing initially wrap your Map<Pair<K1,K2>,V> with your own "DoubleKeyMap".
(And don't forget to properly implement the methods hash and equals in the Pair class!!)
While I also am on board with what you proposed (a pair of values to use as the key), you could also consider making a wrapper which can hold/match both keys. This might get somewhat confusing since you would need to override the equals and hashCode methods and make that work, but it could be a straightforward way of indicating to the next person using your code that the key must be of a special type.
Searching a little bit, I found this post which may be of use to you. In particular, out of the Apache Commons Collection, MultiKeyMap. I've never used this before, but it looks like a decent solution and may be worth exploring.
I would opt for the Map<Pair<K1,K2>, V> solution, because:
it directly expresses what you want to do
is potentially faster because it uses fewer indirections
simplifies the client code (the code that uses the Map afterwards
Logically, you Pair (key1, key2) corresponds to something since it is the key of your map. Therefore you may consider writing your own class having K1 and K2 as parameters and overriding the hashCode() method (plus maybe other methods for more convenience).
This clearly appears to be a "clean" way to solve your problem.
I have used array for the key: like this
Map<Array[K1,K2], V>

Categories