3

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?

4
  • Quick/Efficient in terms of lines of code or in terms of running time, performance? Commented Jun 24, 2010 at 7:04
  • 2
    Any particular reason you're using String[] instead of List<String> in your map? I can't think of very many reasons why the array would be better, and with regards to your question, the way I'm thinking, the list would make it a bit easier. Commented Jun 24, 2010 at 7:04
  • @vodkhang - Performance first, lines of code a bonus. Commented Jun 24, 2010 at 7:10
  • @lauri-lehtinen There was, but it's not a very good one. For the purposes of this question, I've changed it to List<String>. Thanks! Commented Jun 24, 2010 at 7:12

4 Answers 4

2

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.

Sign up to request clarification or add additional context in comments.

3 Comments

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); }
I agree with you Carlos. The put method will not insert the value into the map if the key is already known...
If values has a null value your code will throw a NullPointerException.
1

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.

Comments

1

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

group(values, by(on(CategoryValuePair.class).getCategory()));

2 Comments

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)
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.
0

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;
}

3 Comments

@Fred Well it actually compiled :)
Because you have edit your code... The if clause wasn't present when i wrote my comment...
Oh i have to.. I had used pre and code tags to format my code... which messed up everything... sorry for confusion ...

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.