I have a large enum in Java and I want to break it down into subsets (I think I can do this with EnumSet). I then want to be able to create a hashmap or enummap of only the elements in the EnumSet. How can I achieve this please?
public enum Test { ENUM1, ENUM2, ENUM3, ENUM4, ENUM5 }
EnumSet<Test> testSet = EnumSet.range(ENUM2, ENUM4);
HashMap<testSet, String> testHashMap; <--- Compilation Failure
Edit:
I want to be able to create the hashset to only have Keys for the available enums of the EnumSet and assign a unique string value to each enum in the EnumSet.
Thanks!
testSet is an instance of the EnumSet. You want to define the key type to be EnumSet<Test> instead:
HashMap<EnumSet<Test>, String> testHashMap = new HashMap<>();
...
testHashMap.put(testSet, "string");
It sounds like what you want is a HashMap<Test, String>, and you're going to have to enforce the restriction to the specified range yourself. You can't encode that restriction at the type system level in Java.
I don't think you can get compile time checking as in your example - unless you actually split the enum into multiple smaller enums. At runtime there are some options.
If possible, I would create an unmodifiable view of a map EnumMap<Test, String>. This essentially restricts the map keys to whatever Enum constants you choose.
The actual map is still mutable. If the strings need to change under your control, you can do that internally but only make the immutable map public. If everyone needs to be able to change the strings, you could use something like an unmodifiable EnumMap<Test, StringHolder> and pre-fill it with the the desired enum ranges and and empty holder (StringHolder is a simple pogo, with getter and setter for a single string value. Kind of like a mutable string).
Another option would be to your your own Map type (backed by a HashMap or EnumMap). Whenever a new key is created, check testSet and throw an exception if the key isn't in there.
You'll have to extend HashMap unfortunately. Each time an element is added, you'll have to check it against an EnumSet.
public class EnumSetMap<E, V> extends HashMap<E, V> implements Map<E, V> {
private EnumSet<E> allowed;
public EnumSetMap(EnumSet<E> allowed) {
this.allowed = allowed;
}
#Override
public V put(E key, V value) {
if (allowed.contains(element))
throw new IllegalArgumentException("Key must be in the Enum set.");
return super.put(E, V);
}
}
Your example code would become:
HashMap<Test, String> = new EnumSetMap<Test, String>(testSet);
Related
It seems that HashMap is limited to only one value, and I need a table of values like:
Joe(string) 25(Integer) 2.0(Double)
Steve(string) 41(Integer) 1.6(Double)
etc.
I want to store infomation similarly as in two-dimensional array, but I want it to have different variable types. I've look at various Map-implementing classes, but it seems that they only store value (assigned to a key), or two variables (I need at least three). What class should I use for this?
It sounds like you should be creating a separate class with a String field, an int field and a double field.
Then you can create a map with that as the value type, and whatever type you like as a key. For example:
Map<String, Person> map = new HashMap<>();
// What keys do you really want here?
map.put("foo", new Person("Joe", 25, 2.0));
map.put("bar", new Person("Steve", 41, 1.6));
Or it's possible that you don't even need a map at all at that point:
List<Person> list = new ArrayList<>();
list.add(new Person("Joe", 25, 2.0));
list.add(new Person("Steve", 41, 1.6));
Make class representing data you want to store, eg.
class Person {
String name;
//rest
}
and then make map like Map. Type of map is irrelevant
I would suggest that you create a simple class that stores the integer and double pair, which is then mapped to a String (I assume this is the desired outcome).
HashMap<String, Pair<Integer, Double>> map = new HashMap<String, Pair<Integer, Double>>;
map.put("Steve", new Pair<Integer, Double>(41, 1.6));
Where Pair is defined as
class Pair<T, K> {
public T val1;
public K val2;
public Pair(T val1, K val2){
this.val1 = val1;
this.val2 = val2;
}
}
There are a number of ways to do this.
The best way is the way that is suggested by Jon Skeet and #novy1234. Create a custom class that represents a person (or whatever the rows of the table are). Then use either a Map or a List of that class to represent the "table". (The Map allows you to select one of the fields / columns as a key ... if that is appropriate.)
So you might end up with a HashMap<String, Person> or an ArrayList<Person> ... where Person is your custom class.
A second way would be to represent each row as a Map<String,Object> so that (for example) "name" maps to "Joe", "age" maps to 25 and "height" maps to 2.0. (He is tall.) Then the table could be either a Map or a List of those maps.
A variation of the second way would be a Map<String, Map<String, Object>> where the keys of the outer map are each person's name, the keys of the inner map are the field names; e.g. "age" and "height".
However using a Map<String, Object> to represent a row is not a good Java solution when the set of columns is known. A custom class will use significantly less space than a Map (of any flavour), and a regular getter method is orders of magnitude faster that a Map.get(key) method. In addition, the Map.get(...) method is going to return you an Object that has to be cast to the expected type before it can be used. There is a risk that the typecast will fail at runtime, because you have (somehow) populated the row / map incorrectly.
You should only contemplate using a Map to represent a row in the table if the columns are not known at compile time, or if there are an unmanageably number of columns that are populated sparsely. (Neither is the case here ...)
So, which Map class should you use?
Your alternatives include HashMap, TreeMap, LinkedHashMap and ConcurrentHashMap. Each one has different properties and different target use-cases. However, if your table is small, and in the absence of specific requirements, it probably makes no real difference.
Make a node to store both the integer and double values?
I'm relatively new to Java and I have a question about what type of data structure would be best for my case. I have a set of data which are essentially key-value pairs, however each value may correspond to multiple keys and each key may correspond to multiple values. A simplified example would be:
Red-Apple
Green-Apple
Red-Strawberry
Green-Grapes
Purple-Grapes
Considering the above example, I need to be able to return what color apples I have and/or what red fruits I have. The actual data will generated dynamically based upon an input file where each set will be anywhere from 100-100,000 values and each value may correspond to hundreds of values in the other set.
What would be the most efficient way to store and parse this data? I would prefer a solution as native to java as possible rather than something such as an external database.
This question is related, but I'm not sure how to apply the solution in my case given that I would need to assign multiple values to each key in both directions.
As you can't have duplicate keys in a Map, you can rather create a Map<Key, List<Value>>, or if you can, use Guava's Multimap.
Multimap<String, String> multimap = ArrayListMultimap.create();
multimap.put("Red", "Apple");
multimap.put("Red", "Strawberry");
System.out.println(multimap.get("Red")); // Prints - [Apple, Strawberry]
But the problem is you can't ask for the keys of a given object, I'll keep looking and make and edit if I find something else, hope it helps.
Still, you can make the reverse yourself by iterating the map and finding the keys for the object.
I suggest you use Guava's Table structure. Use color as your row keys and fruit as your column key or the other way round. Specifically, HashBasedTable is well suited for your case.
As per your use case, you wouldn't need to store anything for the values. However, these Tables don't allow null values. You could use a dummy Boolean or any other statistical useful value, i.e. date and time of insertion, user, number of color/fruit pairs, etc.
Table has the methods you need, such as column() and row(). Bear in mind that the docs say that these structures are optimized for row access. This might be OK for you if you plan to access by one key more than by the other.
You can create your own custom data structure
public class MultiValueHashMap<K, V> {
private HashMap<K, ArrayList<V>> multivalueHashMap = new HashMap<K, ArrayList<V>>();
public static void main(String[] args) {
MultiValueHashMap<String, String> multivaluemap = new MultiValueHashMap<String, String>();
multivaluemap.put("Red", "Apple");
multivaluemap.put("Green", "Apple");
multivaluemap.put("Red", "Strawberry");
multivaluemap.put("Green", "Grapes");
multivaluemap.put("Purple", "Grapes");
for(String k : multivaluemap.keySet()){
System.out.println(k + " : " + multivaluemap.get(k).toString());
}
}
public void put(K key, V value){
if (multivalueHashMap.containsKey(key)){
ArrayList<V> values = multivalueHashMap.get(key);
values.add(value);
}else{
ArrayList<V> values = new ArrayList<V>();
values.add(value);
multivalueHashMap.put(key, values);
}
}
public Set<K> keySet(){
return multivalueHashMap.keySet();
}
public ArrayList<V> get(K key){
return multivalueHashMap.get(key);
}
}
The output should be
Red : [Apple, Strawberry]
Purple : [Grapes]
Green : [Apple, Grapes]
Good day all,
Considering the following code example:
import java.util.HashMap;
import java.util.Map;
public class StaticPractice {
private final Map<String, String> mapperMap;
public StaticPractice(){
mapperMap = new HashMap<String, String>();
mapperMap.put("Foo1", "Bar1");
mapperMap.put("Foo2", "Bar1");
mapperMap.put("Foo3", "Bar2");
mapperMap.put("Foo3", "Bar3");
//...
mapperMap.put("MoreFoo", "BarAgain");
}
public void doSomething(){
//use mapperMap
}
}
I am looking for a more succinct way of creating a Map data structure that has a whole lot of constant Strings mapping to a whole lot of other constant Strings. In use, the example is far from "clean" or elegant, and is very verbose (there are alot of predefined constant mappings).
The goal of the class is to map objects referenced by these predefined constant Strings. It is commonplace in my particular code convention to use private static final String for all String constant, this example as well breaks that convention.
Would greatly appreciate any input, the wealth of knowledge from SO contributors always humbles me.
Much thanks.
Edit: Requirement specifies no external files.
One approach would be to create a builder class that generates the map. This has the advantage that you can optimize for concise syntax. You can also do things like making the generated map immutable -- useful if you want to use it as a publically accessible constant.
In your example, I notice that you have more than one key mapping to the same value. So, it would be more concise to have a method that takes a value followed by a list of keys. You can also make it more concise by having the builder return itself so that you can "chain" method calls:
class Builder<K,V> {
final Map<K,V> map = new HashMap<K,V>();
Builder add(V value, K... keys) {
for(K key : keys) {
map.put(key, value);
}
return this;
}
Map<K,V> build() {
return Collections.unmodifiableMap(new HashMap<K,V>(map));
}
}
// Usage:
mapperMap = new Builder<String,String>()
.add("Bar1", "Foo1", "Foo2")
.add("Bar2", "Foo3")
...
.build();
Alternately you might take a look at the Guava ImmutableMap class, which has a builder using the chaining syntax, though it doesn't have a way to map multiple keys to a single value in one call.
I Think you can try using Properties instead of map or initializing the map by reading strings from a configration file.
The most succint way I know is to define your map as an anonymous subclass of HashMap with an instance initializer:
private final Map<String, String> mapperMap =
Collections.unmodifiableMap(new HashMap() {{ // instance initializer
put("Foo1", "Bar1");
put("Foo2", "Bar1");
put("Foo3", "Bar2");
put("Foo3", "Bar3");
}});
If you want it to be a final String, you can always create a class with a couple of constant strings and the use a list of objects of that class.
You can do it like this:
class MapClass {
private static final String key;
private static final String value;
}
List<MapClass> l = new ArrayList<>();
A a = new A(); //classA { }
HashMap<String, Object> hm = new Hashmap<String,Object>();
hm.put("A", a);
My question is, How can i put the Object itself instead of "A" in same declaration?
hm.put(`a??`, a);
You simply cannot do that, the language prohibits it. It would only be possible if your class A is a subclass of String which is not possible, since String is declared as final in Java.
With respect to you interview question: It's not possible due to the generic type parameter that was chosen for the declaration. You can read more about that in Bounded Type Parameters.
A a = new A(); //classA { }
Map<A, A> hm = new Hashmap<A, A>();
hm.put(a, a);
But I do not see any point of putting a->a
If the class held a non-changing decent String field, you could use that.
// the id property must be a String, immutable and unique for each instance!
myMap.put(a.getId(), a);
If you want to make any object as a key in your HashMap, then that object has to be immutable.. Because, you don't want anyone to change your key, after you add them to your HashMap..
Just imagine, if your keys are changed after insertion, you won't ever be able to find your inserted value..
But if your key is immutable, then if anyone tries to change your keys, he will actually create a new one for himself, but you will still have yours..
That is what happens in case you use String as your key in HashMap(They can't be changed).. So, if you want your object to be a key, either you make your class a subclass of String (that you can't do), or, just make your class immutable..
This is actually possible using a raw type, like this:
Object key = ...;
Object value = ...;
Map<String, Integer> map = new HashMap<>();//a normal map
Map rawMap = map; // here is the raw type
rawMap.put(key, value); // it works!
This runs fine, but problems arise when you try to use the generic map later:
Integer value = map.get(key);// ClassCastException (unless value actually is an Integer)
That's why you were told that it's a "dirty trick". You shouldn't use it.
This seems too tricky for me to be doing this correctly.
I have a TreeMap<Double, (user-defined)Object>, of which I am taking a submap:
public static reqObj assignObj(reqObj vArg, int startDate, int endDate){
reqObj vOut=new reqObj();
if (keyAt(vArg.requestObject,startDate)>-1 && keyAt(vArg.requestObject,endDate)>-1){
System.err.println(keyAt(vArg.requestObject,startDate));
System.err.println(keyAt(vArg.requestObject,endDate));
//vOut.requestObject=(TreeMap<Double, dayObj>)
vArg.requestObject.subMap(
keyAt(vArg.requestObject,startDate),
keyAt(vArg.requestObject,endDate));
}
return vOut;
}
This works just as expected, but when I go to cast my sorted map back to (TreeMap) I get the following error:
java.lang.ClassCastException: java.util.TreeMap$SubMap
Any help would be great.
The problem is exactly what the error says: the returned submap is not a standard TreeMap, it is an instance of an implementation-defined inner class. If you look at the declaration of subMap:
public SortedMap subMap(Object fromKey, Object toKey)
all it guarantees is that the returned object implements the SortedMap interface, so that's the only thing you can safely cast to.
That being said, there is no reason to actually cast to a TreeMap because it doesn't provide any additional functionality over what a SortedMap does.