views:

62

answers:

3

Hi folks,

I have a nested map:

Map<Integer, Map<Integer, Double>> areaPrices = new HashMap<Integer, Map<Integer, Double>>();

and this map is populated using the code:

 while(oResult.next())

   {

   Integer areaCode = new Integer(oResult.getString("AREA_CODE"));
   Map<Integer, Double> zonePrices = areaPrices.get(areaCode);
   if(zonePrices==null)
      {
       zonePrices = new HashMap<Integer, Double>();
       areaPrices.put(areaCode, zonePrices);
      }
   Integer zoneCode = new Integer(oResult.getString("ZONE_CODE"));
   Double value = new Double(oResult.getString("ZONE_VALUE"));
   zonePrices.put(zoneCode, value);

   myBean.setZoneValues(areaPrices);

   }

I want to use the value of this Map in another method of the same class. For that I have a bean.

How do I populate it on the bean, so that I can get the ZONE_VALUE in this other method

In my bean I added one new field as:

private Map<Integer, Map<Integer, Double>> zoneValues;

with getter and setter as:

public Map<Integer, Map<Integer, Double>> getZoneValues() {
  return zoneValues;
}

public void setZoneValues(Map<Integer, Map<Integer, Double>> areaPrices) {
  this.zoneValues = areaPrices;
}

What I am looking for to do in the other method is something like this:

Double value = myBean.get(areaCode).get(zoneCode);

How do I make it happen :(

A: 

You can't directly control the second get() call because you have a nested Map, you'll need to return the appropriate nested Map to be able to do what you want. A getter like this should do it:

public Map<Integer, Double> get(Integer areaCode) {
  return zoneValues.get(areaCode);
}

So when the client code calls get(areaCode) a map will be returned that they can then call get(zoneCode) on.

I'd suggest that you refactor to eliminate the nested Maps though, because you can't stop client code from changing the returned Map, the code is tough to read and you'll have problems if you want to add any more functionality - imagine that you want to provide a String description of an area code in future.

Something like a Map<Integer, AreaCode> where AreaCode is an object that contains what you currently have as a nested Map might be a good place to start.

Brabster
Hi Brabster, Thanks for the help. I am a newbie in this :) Give me a minute, I am going to try your solution, if it works then only I can take a chance to improve my code :-( First priority right now is to make it work :D
techoverflow
Also, I just need to change the getter? No changes with setter?
techoverflow
Yeah, you're interested in the behaviour of the getter, so just doing the first bit of my suggestion, altering the getter should allow you to call myBean.get(areaCode).get(zoneCode);
Brabster
Oops, Correction! zoneValue map keys doesnt contain any of the areacodes. Am I missing something?
techoverflow
Please forgive me if I am acting real dumb here.. I just tried your getter and its throwing an error saying:zonevalues cannot be resolved
techoverflow
Should have been zoneValues, sorry! The member variable in your bean.
Brabster
Thanks Brabster. But still the same error. Do I need to declare a zoneValue hashmap in my bean to make it work?
techoverflow
If you have 'private Map<Integer, Map<Integer, Double>> zoneValues;' in your bean, you should be able to resolve it in your getter. Do you still have that declaration?
Brabster
Yes its there. I got it. so that getter will return me a map and I can pass on the key again to fetch the value. Right? I am going test it right now and post you with the result. Thanks for being patient :)
techoverflow
+1  A: 

To start with, all you need is

myBean.getZoneValues(areaCode).get(zoneCode);

the while loop has an annoyance, you need to call myBean.setZoneValues(areaPrices);
out side the while loop

questzen
Hi questzen, thanks :) Moved it outside the while. Still stuck with getter issue :(
techoverflow
Either the values passed for areaCode and zoneCode are not present or the hashmap is empty. You need to inspect the contents using debugger mode. In case you are new to programming, try to grab eclipse IDE, debugging is easier that way.
questzen
Hi questzen, I am using RAD 7, its eclispse based
techoverflow
+2  A: 

I would like to suggest a different, hopefully more readable solution:

public class PriceMap {
  private  Map<Integer, Map<Integer, Double>> priceMap = 
               new HashMap<Integer, Map<Integer, Double>>();

  // You'd use this method in your init
  public Double setPrice(Integer areaCode, Integer zoneCode, Double price) {
    if (!priceMap.containsKey(zoneCode)) {
      priceMap.put(zoneCode, new HashMap<Integer, Double>());
    }
    Map<Integer, Double> areaMap = priceMap.get(zoneCode);
    areaMap.put(areaCode, price);
  }  

  public void getPrice(Integer areaCode, Integer zoneCode) {
    if (!priceMap.containsKey(zoneCode)) {
      // Eek! Exception or return null?
    }
    Map<Integer, Double> areaMap = priceMap.get(zoneCode);
    return areaMap.get(areaCode);
  }
}

I think this is a better, more readable abstraction which, very importantly, makes it easier for you or someone else to read after a few months.

EDIT Added get get

If you're stuck with a get(areaCode).get(zoneCode) (order reversed), but myBean is entirely yours, you could do something like:

public class MyBean {
  // I suppose you have this already
  private  final Map<Integer, Map<Integer, Double>> priceMap = 
               new HashMap<Integer, Map<Integer, Double>>();

  private class LooksLikeAMap implements Map<Integer, Double> {
    private Integer areaCode = areaCode;
    public LooksLikeAMap(Integer areaCode) {
      this.areaCode = areaCode;
    }

    public Double get(Object zoneCode) {
      if (!priceMap.containsKey(zoneCode)) {
        // Eek! Exception or return null?
      }
      Map<Integer, Double> areaMap = priceMap.get(zoneCode);
      return areaMap.get(areaCode);
    }        
    // Implement other methods similarly
  }

  public Map<Integer, Double> get(Integer areaCode) {
    return new LooksLikeAMap(areaCode);
  }  
}

OK, programming in a HTML textarea is not my strong suit, but the idea is clear. Make some Map like structure backed by the complete data set, and initialize that Map structure with the required AreaCode.

If the idea is not clear, post a comment fast as it's late here:)

EDIT

I am an idiot. I thought the data was zone first, then area while the get should be area first, then zone. In this case the Map already has the right structure, first area then zone, so this is not necessary. The get-get is by default if you make

public MyBean {
  public Map<Integer, Double> get(Integer areaCode) {
    return data.get(areaCode);
  }
}
extraneon
Hi extraneon, Thanks for the help. It indeed looks very clear and easy to understand. but I am working on someone else code and I am suppose to follow that flow only. Could you please help me out with the getter solution?
techoverflow
@techoverflow what is the recommended behaviour if the area code or zone code is not known? Now you get a NullPointerException.
extraneon