views:

111

answers:

5

Given the class:

 public class CategoryValuePair
 {
      String category;
      String value;
 }

And a method:

public Map<String,List<String>> convert(CategoryValuePair[] values);

Given that in values we can receive many entries with the same category, I want to convert these into a Map grouped on category.

Is there a quick / efficient way to perform this conversion?

+2  A: 

As far as I know there is not easier way than iterating on values, and then putting the values in the map (like some predefined method).

Map<String, List<String>> map = new HashMap<String, List<String>>();
if (values != null) {
    for (CategoryValuePair cvp : values) {
      List<String> vals = map.get(cvp.category);
      if (vals == null) {
        vals = new ArrayList<String>();
        map.put(cvp.category, vals);
      }
      vals.add(cvp.value);
    }
}

I changed the map values from String[] to List<String> since it seems easier to me to use that so you don't have to hassle with array resizing.

Andrei Fierbinteanu
performance: why put the list into the map every time, only do it if a new list is created. `if (vals == null) { vals = new ArrayList<String>(); map.put(cvp.category, vals); }`
Carlos Heuberger
I agree with you Carlos.The put method will not insert the value into the map if the key is already known...
Fred
If values has a null value your code will throw a NullPointerException.
Fred
good points, thanks
Andrei Fierbinteanu
A: 
public Map<String, List<String>> convert(CategoryValuePair[] values) {
    Map<String, List<String>> toReturn = new HashMap<String, List<String>>();
    if (values != null) {
        for (CategoryValuePair categoryValuePair : values) {
            if (!toReturn.containsKey(categoryValuePair.category)) {
                toReturn.put(categoryValuePair.category, new ArrayList<String>());
            }
            toReturn.get(categoryValuePair.category).add(categoryValuePair.value);
        }
    }
    return toReturn;
}
Fred
A: 

Just for the sake of implementation... The method returns Map and also checks for duplicates in the arrays... though performance wise its heavy ...

public Map<String,String[]> convert(CategoryValuePair[] values)
{
    Map<String, String[]> map = new HashMap<String, String[]>();
    for (int i = 0; i < values.length; i++) {
        if(map.containsKey(values[i].category)){
            Set<String> set = new HashSet<String>(Arrays.asList(map.get(values[i].category)));
            set.add(values[i].value);
            map.put(values[i].category, set.toArray(new String[set.size()]));
        }else {
            map.put(values[i].category, new String[]{values[i].value});
        }
    }

    return map;
}
Favonius
I'm not sure your code could ever compile...
Fred
@FredWell it actually compiled :)
Favonius
Because you have edit your code... The if clause wasn't present when i wrote my comment...
Fred
Oh i have to.. I had used pre and code tags to format my code... which messed up everything... sorry for confusion ...
Favonius
+1  A: 

To make it in fewer lines of code, use Google Collections:

public Map<String, Collection<String>> convert(CategoryValuePair[] values) {
    Multimap<String, String> mmap = ArrayListMultimap.create();
    for (CategoryValuePair value : values) {
        mmap.put(value.category, value.value);
    }
    return mmap.asMap();
}

If you don't want to allow duplicate values, replace ArrayListMultimap with HashMultimap.

True Soft
+1 for not reinventing the wheel
Marty Pitt
+1  A: 

With lambdaj you just need one line of code to achieve that result as it follows:

group(values, by(on(CategoryValuePair.class).getCategory()));
Mario Fusco
I'm a big fan of the lambdaj project, and the library is already in the project in question. I'm not sure why I didn't think of using this.However, in terms of performance, I suspect the Google Collections approach is probably faster. (Correct me if I'm wrong)
Marty Pitt
as vodkhang asked did you mean "quick/Efficient in terms of lines of code or in terms of running time, performance"? If you are looking for something very readable and concise I believe lambdaj could be the best solution (disclaimer: I am the creator of lambdaj). If performance is your biggest concern maybe you should chose Google Collection even if the lambdaj's group feature is one of the best performing, as you can read from the project documentation. My last advice is to give a chance to both solution and write a small harness to compare their performances. Let me know what you will find.
Mario Fusco