Related
I have one Map in java like this:
Map<String index1, Map<String index 2, Object obj>> map = new HashMap<>();
I want to get my Object in the map by using index1 and index2 as lookups.
The easiest way to do this would be to use Guava's Table, if you're willing to use a third party library.
It works like this:
Table<String, String, Object> table = HashBasedTable.create();
table.put(index1, index2, obj);
Object retrievedObject = table.get(index1, index2);
You can add it to your project by following these instructions: How to add Guava to Eclipse project
If you don't want to use Guava, you have a big problem. If you try to insert an element with new first key, you have to make sure the innermap already exists. This means, every time you do put, you have to retrieve the innerMap, see if it exists, and then create it if it does not. You will have to do this every time you call Map.put. Also, you risk throwing a NullPointerException if the inner map doesn't exist when you call get on the inner map.
If you do this, should wrap your Map<String, Map<String, Object> in an outer class to manage these problems, or use Java 8's computeIfAbsent. But the easiest way is to just use Table as above.
If you make your own class to use instead of Table, it would be something like:
public class DoubleMap<R, C, V> {
private final Map<R, Map<C, V>> backingMap;
public DoubleMap() {
this.backingMap = new HashMap<>();
}
public V get(R row, C column) {
Map<C, V> innerMap = backingMap.get(row);
if(map == null) return null;
else return innerMap.get(column);
}
public void put(R row, C column, V value) {
Map<C, V> innerMap = backingMap.get(row);
if(innerMap == null) {
innerMap = new HashMap<C, V>();
backingMap.put(row, innerMap);
}
innerMap.put(column, value);
}
}
You would use this class by doing:
DoubleMap<String, String, Object> map = new DoubleMap();
Note that this answer has a lot less features than the Guava version.
Getting a Value from a Map
If I understand your question, then with an index a and b that might look like (guarding against null with a ternary or Conditional Operator ? :),
Object obj = (map.get("a") == null) ? null : map.get("a").get("b");
Using a Generic Type
And you might be more specific, like
Map<String, Map<String, Something>> map = new HashMap<>();
Something s = (map.get("a") == null) ? null : map.get("a").get("b");
Adding values to the Map
Assuming you want to add your Something value to the map that could be done with something like,
Map<String, Map<String, Something>> map = new HashMap<>();
if (map.get("a") == null) {
map.put("a", new HashMap<>());
}
map.get("a").put("b", value);
If you don't need regular access to the entire "row", but just quick access to each cell you can use the built-in Map.Entry as your key:
Map<Map.Entry<String, String>, Object> table = new Map<>();
table.put(new Map.SimpleEntry("index1", "index2"), "Hello world");
Alternatively, if you're willing to go with something third-party, several someones have already implemented tuples for Java.
If you are in a situation where you cannot pull in a third-party library easily, but you don't like the semantics of Map.Entry (which is written in terms of keys and values) you can write your own Pair class to have the same effect.
As my understanding, you can do like:
Map<String, Map<String, Object> map= new HashMap();
Map<String, Object> subMap = map.get("index1");
if(subMap != null) {
Object obj = subMap.get("index2");
}
The best solution probably depends on how this map is intended to be used:
Is it used in a limited scope, or is it part of a public API?
Are the "indices" always of type String, or do they have to be generic?
Will it always be two indices, or may you need more indices later?
...
A pragmatic solution focussed on the question as you described it would be to introduce a StringPair class that can be used for indexing. This saves you from the hassle of doing 2D-lookups of inner maps (and possible cleanups when the inner maps become empty!), does not require any third-party libraries, and is readable and efficient.
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Objects;
public class StringPairMapTest
{
public static void main(String[] args)
{
Map<StringPair, Object> map = new LinkedHashMap<StringPair, Object>();
map.put(StringPair.of("A","B"), 12);
map.put(StringPair.of("C","D"), 34);
System.out.println(map.get(StringPair.of("A","B")));
System.out.println(map.get(StringPair.of("C","D")));
System.out.println(map.get(StringPair.of("X","Y")));
}
}
class StringPair
{
private final String s0;
private final String s1;
static StringPair of(String s0, String s1)
{
return new StringPair(s0, s1);
}
private StringPair(String s0, String s1)
{
this.s0 = s0;
this.s1 = s1;
}
#Override
public String toString()
{
return "("+s0+","+s1+")";
}
#Override
public int hashCode()
{
return Objects.hash(s0, s1);
}
#Override
public boolean equals(Object obj)
{
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
StringPair other = (StringPair) obj;
return Objects.equals(s0, other.s0) && Objects.equals(s1, other.s1);
}
}
Generalizations to a Pair<T> or Tuple<S,T> would be possible, of course, but this did not seem to be what you have been looking for...
When writing a Java program, I face a problem as follows:
Map<Object, Map<Object, Map<Object, Object>>> map = new HashMap<>();
/**
* put operations
**/
Map<Object, Map<Object, Object>> a = null;
Map<Object, Object> b = null;
Object c = null;
a = map.get(/*some object*/);
if(a != null) {
b = a.get(/*some object*/);
}
if(b != null) {
c = b.get(/*some object*/);
}
if(c != null) {
/*do what I want to do*/
}
If I want to be sure c is not null, I need to add an "if" three times to ensure that the code can run without exception. Is there a better way to do it?
Encapsulate required functionality in a class implementing something like this:
interface ThreeKeysMap {
void put(Object keyA, Object keyB, Object keyC, Object value);
Object get(Object keyA, Object keyB, Object keyC);
}
Alternatively, you could create a class for your composite key:
public class ThreeKey {
public Object keyA;
public Object keyB;
public Object keyC;
// TODO: MUST override equals and hashCode methods or map won't work!!!!
}
and use it as a key for your map: Map<ThreeKey, Object> map = new HashMap<>();
I think that the getOrDefault-method of the Map interface could work here. Especially if you combine it with the Optional class as follows:
Map<Object, Map<Object, Map<Object, Object>>> map = new HashMap<>();
Map<Object, Map<Object, Object>> a = map.getOrDefault("", Collections.emptyMap());
Map<Object, Object> b = a.getOrDefault("", Collections.emptyMap());
Optional.ofNullable(b.get("")).ifPresent(c -> {/* Do what I want to do */});
This way you simply use getOrDefault to retrieve empty maps (which I personally like better than null values. The Optional.ofNullable is a null-safe way of creating an Optional object and you can do what you want to do in the lambda expression.
Both Optional and Map.getOrDefault are part of Java 8.
You can create a class Key<T,E> that will hold your first pairs of objects, and than create a map
Map<Key<T,E>, Object>
This seems much more neat to me, because it seems you use the first two objects as a key, and the nested dictionary approach is less elegant for such a task.
Remember that if you follow this approach - you have to override equals() and hashCode(), and depending on usages - sometimes also compareTo()
Can I access my nestedMap in my iterator when the nestedMap is created in the put() method, like this:
#Override
public String put(final String row, final String column, final String value) {
/**
* Second map which is contained by centralMap, that contain Strings as
* Keys and Values.
*/
Map<String, String> nestedMap;
if (centralMap.containsKey(row))
nestedMap = centralMap.get(row);
else
nestedMap = new HashMap<String, String>();
if (!nestedMap.containsKey(column))
counter++;
centralMap.put(row, nestedMap);
return nestedMap.put(column, value);
}
and the centralMap is declared as an Object-Variable,
private final Map<String, Map<String, String>> centralMap;
but instantiated just in the constructor, like this:
centralMap = new HashMap<String, Map<String, String>>();
the method i'm trying to implement is the remove method:
#Override
public void remove() {
for (Map<String, String> map : centralMap.values()) {
map = centralMap.get(keyName);
iteratorNested.remove();
if (map.size() <= 0)
iteratorCentral.remove();
}
}
Thanks a lot!
Not sure what you're asking exactly, but I think this is a little easier to read:
#Override
public String put(final String row, final String column, final String value) {
/**
* Second map which is contained by centralMap, that contain Strings as
* Keys and Values.
*/
Map<String, String> nestedMap = centralMap.get(row);
if (nestedMap == null) {
nestedMap = new HashMap<String, String>();
centralMap.put(row,nestedMap);
}
if (!nestedMap.containsKey(column))
counter++;
centralMap.put(row, nestedMap);
return nestedMap.put(column, value);
}
I can't quite understand what you're doing in the second stanza, so can't help you improve that. And I don't see an iterator as referred to in your question.
You're making me guess, but maybe ELSEWHERE in your program (it would really help to see more code, and a specific function prototype or statement of behavior you're seeking) you want to be able to iterate through the contents of the centralMap instance, and nested instances of nestedMap. Yes you can.
public void iterateOverAllNested()
{
for (Map.Entry<String,Map<String,String>> nested : centralMap) {
final String centralKey = nested.key();
final Map<String,String> nestedMap = nested.value();
System.out.println("Central map row/column: "+centralKey);
for (Map.Entry<String,String> entry : nestedMap) {
System.out.println(" key="+entry.key()+", value="+entry.value());
}
}
}
Note that this smells. Nested maps of untyped Strings are probably wrong. Any chance you've been writing Perl recently? I suggest you write a second SO question asking about a good data structure for your specific problem. You can include this code as your starting place, and folks will likely offer a cleaner solution.
How can I create and fetch associative arrays in Java like I can in PHP?
For example:
$arr[0]['name'] = 'demo';
$arr[0]['fname'] = 'fdemo';
$arr[1]['name'] = 'test';
$arr[1]['fname'] = 'fname';
Java doesn't support associative arrays, however this could easily be achieved using a Map. E.g.,
Map<String, String> map = new HashMap<String, String>();
map.put("name", "demo");
map.put("fname", "fdemo");
// etc
map.get("name"); // returns "demo"
Even more accurate to your example (since you can replace String with any object that meet your needs) would be to declare:
List<Map<String, String>> data = new ArrayList<>();
data.add(0, map);
data.get(0).get("name");
See the official documentation for more information
Java doesn't have associative arrays like PHP does.
There are various solutions for what you are doing, such as using a Map, but it depends on how you want to look up the information. You can easily write a class that holds all your information and store instances of them in an ArrayList.
public class Foo{
public String name, fname;
public Foo(String name, String fname){
this.name = name;
this.fname = fname;
}
}
And then...
List<Foo> foos = new ArrayList<Foo>();
foos.add(new Foo("demo","fdemo"));
foos.add(new Foo("test","fname"));
So you can access them like...
foos.get(0).name;
=> "demo"
You can accomplish this via Maps. Something like
Map<String, String>[] arr = new HashMap<String, String>[2]();
arr[0].put("name", "demo");
But as you start using Java I am sure you will find that if you create a class/model that represents your data will be your best options. I would do
class Person{
String name;
String fname;
}
List<Person> people = new ArrayList<Person>();
Person p = new Person();
p.name = "demo";
p.fname = "fdemo";
people.add(p);
Look at the Map interface, and at the concrete class HashMap.
To create a Map:
Map<String, String> assoc = new HashMap<String, String>();
To add a key-value pair:
assoc.put("name", "demo");
To retrieve the value associated with a key:
assoc.get("name")
And sure, you may create an array of Maps, as it seems to be what you want:
Map<String, String>[] assoc = ...
There is no such thing as associative array in Java. Its closest relative is a Map, which is strongly typed, however has less elegant syntax/API.
This is the closest you can get based on your example:
Map<Integer, Map<String, String>> arr =
org.apache.commons.collections.map.LazyMap.decorate(
new HashMap(), new InstantiateFactory(HashMap.class));
//$arr[0]['name'] = 'demo';
arr.get(0).put("name", "demo");
System.out.println(arr.get(0).get("name"));
System.out.println(arr.get(1).get("name")); //yields null
Well i also was in search of Associative array and found the List of maps as the best solution.
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class testHashes {
public static void main(String args[]){
Map<String,String> myMap1 = new HashMap<String, String>();
List<Map<String , String>> myMap = new ArrayList<Map<String,String>>();
myMap1.put("URL", "Val0");
myMap1.put("CRC", "Vla1");
myMap1.put("SIZE", "Vla2");
myMap1.put("PROGRESS", "Vla2");
myMap.add(0,myMap1);
myMap.add(1,myMap1);
for (Map<String, String> map : myMap) {
System.out.println(map.get("URL"));
}
//System.out.println(myMap);
}
}
Java equivalent of Perl's hash
HashMap<Integer, HashMap<String, String>> hash;
Java doesn't have associative arrays, the closest thing you can get is the Map interface
Here's a sample from that page.
import java.util.*;
public class Freq {
public static void main(String[] args) {
Map<String, Integer> m = new HashMap<String, Integer>();
// Initialize frequency table from command line
for (String a : args) {
Integer freq = m.get(a);
m.put(a, (freq == null) ? 1 : freq + 1);
}
System.out.println(m.size() + " distinct words:");
System.out.println(m);
}
}
If run with:
java Freq if it is to be it is up to me to delegate
You'll get:
8 distinct words:
{to=3, delegate=1, be=1, it=2, up=1, if=1, me=1, is=2}
Use ArrayList < Map < String, String > >
Here a code sample :
ArrayList<Map<String, String>> products = new ArrayList<Map<String, String>>();
while (iterator.hasNext()) {
Map<String, String> product = new HashMap<String, String>();
Element currentProduct = iterator.next();
product.put("id",currentProduct.get("id"));
product.put("name" , currentProduct.get("name") );
products.add(product );
}
System.out.println("products : " + products);
Output :
products : [{id=0001, name=prod1}, {id=0002, name=prod2}]
Associative arrays in Java like in PHP :
SlotMap hmap = new SlotHashMap();
String key = "k01";
String value = "123456";
// Add key value
hmap.put( key, value );
// check if key exists key value
if ( hmap.containsKey(key)) {
//.....
}
// loop over hmap
Set mapkeys = hmap.keySet();
for ( Iterator iterator = mapkeys.iterator(); iterator.hasNext();) {
String key = (String) iterator.next();
String value = hmap.get(key);
}
More info, see Class SoftHashMap : https://shiro.apache.org/static/1.2.2/apidocs/org/apache/shiro/util/SoftHashMap.html
Object[][] data = {
{"mykey1", "myval1"},
{"mykey2", "myval2"},
{new Date(), new Integer(1)},
};
Yes, this require iteration for searchting value by key, but if you need all of them, this will be the best choice.
In JDK 1.5 (http://tinyurl.com/3m2lxju) there is even a note: "NOTE: This class is obsolete. New implementations should implement the Map interface, rather than extending this class."
Regards, N.
Actually Java does support associative arrays they are called dictionaries!
Thinking more about it, I would like to throw out tuples as a more general-purpose way of dealing with this problem. While tuples are not native to Java, I use Javatuples to provide me the same functionality which would exist in other languages. An example of how to deal with the question asked is
Map<Pair<Integer, String>, String> arr = new HashMap<Pair<Integer, String>, String>();
Pair p1 = new Pair(0, "name");
arr.put(p1, "demo");
I like this approach because it can be extended to triples and other higher ordered groupings with api provided classes and methods.
Regarding the PHP comment 'No, PHP wouldn't like it'. Actually, PHP would keep on chugging unless you set some very restrictive (for PHP) exception/error levels, (and maybe not even then).
What WILL happen by default is that an access to a non existing variable/out of bounds array element 'unsets' your value that you're assigning to. NO, that is NOT null. PHP has a Perl/C lineage, from what I understand. So there are: unset and non existing variables, values which ARE set but are NULL, Boolean False values, then everything else that standard langauges have. You have to test for those separately, OR choose the RIGHT evaluation built in function/syntax.
i am reading data from a text file and want to store HashMap in another HashMap..
HashMap<string,HashMap<string,value>>
how to store data and retrieve it?
any sample code will be appreciated...
thank u
Example:
Creating and populating the maps
Map<String, Map<String, Value>> outerMap = new HashMap<String, HashMap<String, Value>>();
Map<String, Value> innerMap = new HashMap<String, Value>();
innerMap.put("innerKey", new Value());
Storing a map
outerMap.put("key", innerMap);
Retrieving a map and its values
Map<String, Value> map = outerMap.get("key");
Value value = map.get("innerKey");
Creating two Simple Hashmaps: InnerMap and OuterMap
HashMap<String, HashMap<String, String>> outerMap = new HashMap<String, HashMap<String,String>>();
HashMap<String, String> innerMap = new HashMap<String, String>();
Populating the HashMaps
innerMap.put("InnerKey", "InnerValue");
outerMap.put("OuterKey", innerMap);
Retreiving values from HashMaps
String value = ((HashMap<String, String>)outerMap.get("OuterKey")).get("InnerKey").toString();
System.out.println("Retreived value is : " + value);
You get something that looks like a 2 dimensions HashMap, so to say. Which means you need 2 String to store a value, and also to retrieve one.
You could, for example write a class to wrap that complexity, like that (untested code):
public class HashMap2D<T> {
private HashMap<String,HashMap<String,T>> outerMap;
public HashMap2D() {
outerMap = new HashMap<String,HashMap<String,T>>();
}
public void addElement(String key1, String key2, T value) {
innerMap=outerMap.get(key1);
if (innerMap==null) {
innerMap = new HashMap<String,T>();
outerMap.put(key1,innerMap);
}
innerMap.put(key2,value);
}
public T getElement(String key1, String key2) {
Hashmap innerMap = outerMap.get(key1);
if (innerMap==null) {
return null;
}
return innerMap.get(key2);
}
}
If you want methods to process more than one data at a time, it's more complicated, but follows the same principles.
This will solve the same problem using one map (although, this does not directly answer your question) by flattening two nested maps into one big map, using a double-key.
public class Key2D{
private final String outer;
private final String inner;
public Key2D(String outer, String inner){
this.outer = outer;
this.inner = inner;
}
//include default implementations for
//Object.equals(Object) and Object.hashCode()
//Tip: If you're using Eclipse it can generate
//them for you.
}
Then just create one map with double-key:
Map<Key2D, Value> map = new HashMap<Key2D, Value>();
map.put(new Key2D("outerKey", "innerKey"), "Value");
map.get(new Key2D("outerKey", "innerKey")); // yields "Value"
This gives a shorter solution. Performance wise it's probably about the same. Memory performance is probably slightly better (just guessing, though).
HashMap in HashMap will cause problems in readability especially when it goes beyond two levels. I assume that when you read data from a text file you want to categorize the inputs from rows and columns which should be similar to multi-level categories or category within a category. If you can post the sample data and your intention, I could come up with a Custom class example.
public class Category {
private List<Category> subCategories;
private List<Item> items;
}
The above data structure will help you solve any level of nesting while categorizing data. This example is specific to a store items' classification.