emeryville
emeryville

Reputation: 49

how to use a single key for multiple entries in nested maps in java

I have an issue where using nested maps might not be the ideal solution , but need some feedback

Here is the generics structure that exists, where the fruit, vegetable, toys are keys ina map which in turn have another map associated where fresh, notfresh, rotten are keys of Map "b"

       private Map<String, Commodity> Comm = new HashMap<String, Commodity>();
       for (Map.Entry<String, Map<String, Object>> e : this.entrySet()) {
          Comm.put(e.getKey(), getCommodity(e.getValue(), e.getKey()));
        }

        private Commodity getCommodity(Map<String, Object> m, String section) {
           return new Commodity(m, section);
        }


  Fruit=> Fresh=>object
          notFresh=>object
          rotten=>object

  Vegetable=> fresh=> object
             notfresh=>object
             rotten=>object
  Toys=> fresh=>object
        notfresh=>object
        rotten=>object

However, i need to introduce another key called "season" where if the season is mentioned for a commodity, then the commodity comes under teh season otherwise stays as mentioned previously.

   i.e 
  Fruit=> winter =>Fresh=>object
                  notFresh=>object
                  rotten=>object

  Vegetable=> fresh=> object
              notfresh=>object
              rotten=>object

  Toys=> summer => fresh=>object
                   notfresh=>object
                   rotten=>object 

So in this case, fruits and toys have a season mentioned , in that case, it needs to look under winter for fruits and summer for toys. How can i acheive this complex map structure in java

Upvotes: 0

Views: 164

Answers (3)

Yohji
Yohji

Reputation: 170

Maybe you could use an object to express the key of the map. The java HashMap use the hashCode of the object for fast comparison - it fallback on equals when the key collide (@see HashMap.getEntry(Object key)).

class Key {

   Item item; // fruit, toys or vegetable
   Season season; // an enum for the season

   // Constructor

   public int hashCode()
   {
       int hash = 1;
       hash *= 31 + item.hashCode();
       hash *= 31 + season.hashCode();

       return hash;
   }

   public boolean equals(Object obj)
   {
       return false; // implementing the equals too
   }
}

Map<Key, Commodity> store = new HashMap<>();
store.put(
   new Key(new Item("Fruit"), Season.FRESH),
   new Commodity("asd")
);
store.put(
   new Key(new Item("Fruit"), Season.NOT_FRESH),
   new Commodity("qwe")
);
store.put(
   new Key(new Item("Vegetable"), Season.ROTTEN),
   new Commodity("zxc")
);

Upvotes: 1

Teena George
Teena George

Reputation: 198

Like Thomas said, this is not the ideal solution. However, just for the sake of testing it, here you go:

I guess I understood the structure correctly. If not please suggest.

 Map<String, Map<String, Map<String,Commodity>>> root = new HashMap<String, Map<String,Map<String,Commodity>>>();
     Map<String, Commodity> leaf = new HashMap<String, Commodity>();
     leaf.put("fresh", new Commodity("name1", "type1"));
     leaf.put("notFresh", new Commodity("name2", "type2"));
     leaf.put("rotten", new Commodity("name3", "type3"));
     Map<String, Map<String,Commodity>> mid = new HashMap<String, Map<String,Commodity>>();
     mid.put("summer", leaf);
     mid.put("winter", leaf);
     root.put("vegetable", mid);
     root.put("fruit", mid);

    for (Entry<String, Map<String, Map<String, Commodity>>> middle: root.entrySet()) {
         Map<String, Map<String,Commodity>> midVal= middle.getValue();
         System.out.println("Type: "+ middle.getKey());
         for (Entry<String, Map<String, Commodity>> leaves : midVal.entrySet()) {
             Map<String,Commodity> leafVal = leaves.getValue();
             System.out.println("Season: " + leaves.getKey());
             for (Entry<String, Commodity> leafValNames : leafVal.entrySet()) {
                System.out.println("key: "+ leafValNames.getKey() + "value: " + leafValNames.getValue());
            }
        }
    }

}

This outputs

Type: fruit
Season: winter
key: rottenvalue: test.Commodity@8def646
key: freshvalue: test.Commodity@8def63c
key: notFreshvalue: test.Commodity@8def641
Season: summer
key: rottenvalue: test.Commodity@8def646
key: freshvalue: test.Commodity@8def63c
key: notFreshvalue: test.Commodity@8def641
Type: vegetable
Season: winter
key: rottenvalue: test.Commodity@8def646
key: freshvalue: test.Commodity@8def63c
key: notFreshvalue: test.Commodity@8def641
Season: summer
key: rottenvalue: test.Commodity@8def646
key: freshvalue: test.Commodity@8def63c
key: notFreshvalue: test.Commodity@8def641

The map looks like:

root = 
{vegetable={winter={rotten=test.Commodity@8df1515, fresh=test.Commodity@8df150b, notFresh=test.Commodity@8df1510}, summer={rotten=test.Commodity@8df1515, fresh=test.Commodity@8df150b, notFresh=test.Commodity@8df1510}}}

mid = 
{winter={rotten=test.Commodity@8df1515, fresh=test.Commodity@8df150b, notFresh=test.Commodity@8df1510}, summer={rotten=test.Commodity@8df1515, fresh=test.Commodity@8df150b, notFresh=test.Commodity@8df1510}}

leaf = 
{rotten=test.Commodity@8df1515, fresh=test.Commodity@8df150b, notFresh=test.Commodity@8df1510}

Upvotes: 0

Thomas Uhrig
Thomas Uhrig

Reputation: 31605

You are right it "might not be the ideal solution". Maps are mechanism to hold a key and a value. A simple mapping if you want so. They are not made to build complicated data structures as you are trying to do. As you see by yourself, it gets very complicated and strange. So do not do this!

Make your own classes instead. Classes are the Java-way to make data structures. First, make a sketch how your data looks:

  • You have a class which holds all your products (lets call it shop)
  • This shop has different categories (toys, vegetables)
  • Each category has one or more seasons
  • You have four seasons (which can hold products)
  • And you have your actual products (which can be an apple for example which could be rotten)

Correct me if I am wrong, but that is how I understood your question. If I am wrong, you can correct the details by your own.

Now we have 5 bullet points and we can make 5 classes out of them. I do it without getters and setters to keep it short:

class Shop {
    List<Category> categories;
}

class Category {    
    String name;
    List<Season> seasons;
}

class Season {
    String name;
    List<Products> products;
}

class Product {
    String name;
    boolean isRotten;
}

Now you can use this to put you shop together:

Shop myShop = new Shop();

Category toys = new Category();
Category fruits = new Category();

myShop.categories.add(toys);
myShop.categories.add(fruits);

Season summer = new Season();

fruits.seasons.add(summer);

Product apple = new Product();
Product pineapple = new Product();
Product banana = new Product();

summer.products.add(apple);
summer.products.add(pineapple);
summer.products.add(banana);

banana.isRotten = true;

Note:

  • You would do this with getter and setter methods.
  • Since there are only four seasons, you would create some static objects to represent them.
  • There are many more ways to do that, this is just a fast one to point you to the direction

Upvotes: 1

Related Questions