So I have the following HashMap:
HashMap<String, List<someDataType>> map;
I want to create a new HashMap that is only composed of the k/v pairs in map that have a value (the list) whose length is less than a certain "x". The only way I know how to do this is to iterate through the HashMap and put k/v pairs into a new HashMap. Is there a more concise way to achieve what I'm looking for? Thanks.
Using guava:
Map<String, List<String>> newMap =
Maps.filterEntries(originalMap, new MyEntryPredicate(10));
where:
private static class MyEntryPredicate implements Predicate<Map.Entry<String, List<String>>> {
// max list length, exclusive
private int maxLength;
private MyEntryPredicate(int maxLength) {
this.maxLength = maxLength;
}
#Override
public boolean apply(Map.Entry<String, List<String>> input) {
return input != null && input.getValue().size() < maxLength;
}
}
If the Guava library is available to your project, you could use Maps.filterValues (somewhat echoing Keith's answer):
final int x = 42;
Map<String, List<String>> filteredMap =
Maps.filterValues(map, new Predicate<Collection<?>>() {
#Override
public boolean apply(final Collection<?> collection) {
return collection.size() < x;
}
});
Map<String, List<String>> filteredMapCopy = ImmutableMap.copyOf(filteredMap);
Note the need for a copy because filterValues returns a filtered view of the original map.
Update: with Java 8 you can simplify the predicate to a lambda expression:
Map<String, List<String>> filteredMap = Maps.filterValues(map, list -> list.size() < x);
Nowadays (Java 8+) this could be done with streams:
Predicate<Map.Entry<String, List<String>>> test = entry -> entry.getValue().size() <= x; // note this is java.util.function.Predicate
Map<String, List<String>> filteredMap = map.entrySet().stream().filter(test)
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
This helps to avoid the dependency to guava which might be undesired.
You may want to look at the Guava library from Google. There's an enormous number of Collections and Map related utils in there, which let you do complex stuff quite concisely. An example of what you can do is:
Iterable<Long> list =
Iterables.limit(
Iterables.filter(
Ordering.natural()
.reverse()
.onResultOf(new Function<Long, Integer>() {
public Integer apply(Long id) {
return // result of this is for sorting purposes
}
})
.sortedCopy(
Multisets.intersection(set1, set2)),
new Predicate<Long>() {
public boolean apply(Long id) {
return // whether to filter this id
}
}), limit);
I'm sure you can find something in there which can do what you're looking for :-)
Going along with the other Guava examples, you can use Guava's MultiMaps:
final MultiMap<K, V> mmap = ArrayListMultiMap.create();
// do stuff.
final int limit = 10;
final MultiMap<K, V> mmapView =
MultiMaps.filterKeys(mmap, new Predicate<K>(){
public boolean apply(K k) {
return mmap.get(k).size() <= limit;
}
});
The MultiMaps.newListMultiMap method takes arguments you don't want to provide. You can't use MultiMaps.filterValues or .filterEntries here because those use the individual values, not the lists of values. On the other hand, mmap.get(k) never returns null. You cam, of course, use a static inner class that you pass mmap and limit to instead of using anonymous inner classes.
Alternatevely you can make a copy of the original map and iterate over the values removing those whose length is less than x.
Related
I want to translate a List of objects into a Map using Java 8's streams and lambdas.
This is how I would write it in Java 7 and below.
private Map<String, Choice> nameMap(List<Choice> choices) {
final Map<String, Choice> hashMap = new HashMap<>();
for (final Choice choice : choices) {
hashMap.put(choice.getName(), choice);
}
return hashMap;
}
I can accomplish this easily using Java 8 and Guava but I would like to know how to do this without Guava.
In Guava:
private Map<String, Choice> nameMap(List<Choice> choices) {
return Maps.uniqueIndex(choices, new Function<Choice, String>() {
#Override
public String apply(final Choice input) {
return input.getName();
}
});
}
And Guava with Java 8 lambdas.
private Map<String, Choice> nameMap(List<Choice> choices) {
return Maps.uniqueIndex(choices, Choice::getName);
}
Based on Collectors documentation it's as simple as:
Map<String, Choice> result =
choices.stream().collect(Collectors.toMap(Choice::getName,
Function.identity()));
If your key is NOT guaranteed to be unique for all elements in the list, you should convert it to a Map<String, List<Choice>> instead of a Map<String, Choice>
Map<String, List<Choice>> result =
choices.stream().collect(Collectors.groupingBy(Choice::getName));
Use getName() as the key and Choice itself as the value of the map:
Map<String, Choice> result =
choices.stream().collect(Collectors.toMap(Choice::getName, c -> c));
Most of the answers listed, miss a case when the list has duplicate items. In that case there answer will throw IllegalStateException. Refer the below code to handle list duplicates as well:
public Map<String, Choice> convertListToMap(List<Choice> choices) {
return choices.stream()
.collect(Collectors.toMap(Choice::getName, choice -> choice,
(oldValue, newValue) -> newValue));
}
Here's another one in case you don't want to use Collectors.toMap()
Map<String, Choice> result =
choices.stream().collect(HashMap<String, Choice>::new,
(m, c) -> m.put(c.getName(), c),
(m, u) -> {});
One more option in simple way
Map<String,Choice> map = new HashMap<>();
choices.forEach(e->map.put(e.getName(),e));
For example, if you want convert object fields to map:
Example object:
class Item{
private String code;
private String name;
public Item(String code, String name) {
this.code = code;
this.name = name;
}
//getters and setters
}
And operation convert List To Map:
List<Item> list = new ArrayList<>();
list.add(new Item("code1", "name1"));
list.add(new Item("code2", "name2"));
Map<String,String> map = list.stream()
.collect(Collectors.toMap(Item::getCode, Item::getName));
If you don't mind using 3rd party libraries, AOL's cyclops-react lib (disclosure I am a contributor) has extensions for all JDK Collection types, including List and Map.
ListX<Choices> choices;
Map<String, Choice> map = choices.toMap(c-> c.getName(),c->c);
You can create a Stream of the indices using an IntStream and then convert them to a Map :
Map<Integer,Item> map =
IntStream.range(0,items.size())
.boxed()
.collect(Collectors.toMap (i -> i, i -> items.get(i)));
I was trying to do this and found that, using the answers above, when using Functions.identity() for the key to the Map, then I had issues with using a local method like this::localMethodName to actually work because of typing issues.
Functions.identity() actually does something to the typing in this case so the method would only work by returning Object and accepting a param of Object
To solve this, I ended up ditching Functions.identity() and using s->s instead.
So my code, in my case to list all directories inside a directory, and for each one use the name of the directory as the key to the map and then call a method with the directory name and return a collection of items, looks like:
Map<String, Collection<ItemType>> items = Arrays.stream(itemFilesDir.listFiles(File::isDirectory))
.map(File::getName)
.collect(Collectors.toMap(s->s, this::retrieveBrandItems));
I will write how to convert list to map using generics and inversion of control. Just universal method!
Maybe we have list of Integers or list of objects. So the question is the following: what should be key of the map?
create interface
public interface KeyFinder<K, E> {
K getKey(E e);
}
now using inversion of control:
static <K, E> Map<K, E> listToMap(List<E> list, KeyFinder<K, E> finder) {
return list.stream().collect(Collectors.toMap(e -> finder.getKey(e) , e -> e));
}
For example, if we have objects of book , this class is to choose key for the map
public class BookKeyFinder implements KeyFinder<Long, Book> {
#Override
public Long getKey(Book e) {
return e.getPrice()
}
}
I use this syntax
Map<Integer, List<Choice>> choiceMap =
choices.stream().collect(Collectors.groupingBy(choice -> choice.getName()));
It's possible to use streams to do this. To remove the need to explicitly use Collectors, it's possible to import toMap statically (as recommended by Effective Java, third edition).
import static java.util.stream.Collectors.toMap;
private static Map<String, Choice> nameMap(List<Choice> choices) {
return choices.stream().collect(toMap(Choice::getName, it -> it));
}
Another possibility only present in comments yet:
Map<String, Choice> result =
choices.stream().collect(Collectors.toMap(c -> c.getName(), c -> c)));
Useful if you want to use a parameter of a sub-object as Key:
Map<String, Choice> result =
choices.stream().collect(Collectors.toMap(c -> c.getUser().getName(), c -> c)));
Map<String, Set<String>> collect = Arrays.asList(Locale.getAvailableLocales()).stream().collect(Collectors
.toMap(l -> l.getDisplayCountry(), l -> Collections.singleton(l.getDisplayLanguage())));
This can be done in 2 ways. Let person be the class we are going to use to demonstrate it.
public class Person {
private String name;
private int age;
public String getAge() {
return age;
}
}
Let persons be the list of Persons to be converted to the map
1.Using Simple foreach and a Lambda Expression on the List
Map<Integer,List<Person>> mapPersons = new HashMap<>();
persons.forEach(p->mapPersons.put(p.getAge(),p));
2.Using Collectors on Stream defined on the given List.
Map<Integer,List<Person>> mapPersons =
persons.stream().collect(Collectors.groupingBy(Person::getAge));
Here is solution by StreamEx
StreamEx.of(choices).toMap(Choice::getName, c -> c);
Map<String,Choice> map=list.stream().collect(Collectors.toMap(Choice::getName, s->s));
Even serves this purpose for me,
Map<String,Choice> map= list1.stream().collect(()-> new HashMap<String,Choice>(),
(r,s) -> r.put(s.getString(),s),(r,s) -> r.putAll(s));
If every new value for the same key name has to be overridden:
public Map < String, Choice > convertListToMap(List < Choice > choices) {
return choices.stream()
.collect(Collectors.toMap(Choice::getName,
Function.identity(),
(oldValue, newValue) - > newValue));
}
If all choices have to be grouped in a list for a name:
public Map < String, Choice > convertListToMap(List < Choice > choices) {
return choices.stream().collect(Collectors.groupingBy(Choice::getName));
}
List<V> choices; // your list
Map<K,V> result = choices.stream().collect(Collectors.toMap(choice::getKey(),choice));
//assuming class "V" has a method to get the key, this method must handle case of duplicates too and provide a unique key.
As an alternative to guava one can use kotlin-stdlib
private Map<String, Choice> nameMap(List<Choice> choices) {
return CollectionsKt.associateBy(choices, Choice::getName);
}
List<Integer> listA = new ArrayList<>();
listA.add(1);
listA.add(5);
listA.add(3);
listA.add(4);
System.out.println(listA.stream().collect(Collectors.toMap(x ->x, x->x)));
String array[] = {"ASDFASDFASDF","AA", "BBB", "CCCC", "DD", "EEDDDAD"};
List<String> list = Arrays.asList(array);
Map<Integer, String> map = list.stream()
.collect(Collectors.toMap(s -> s.length(), s -> s, (x, y) -> {
System.out.println("Dublicate key" + x);
return x;
},()-> new TreeMap<>((s1,s2)->s2.compareTo(s1))));
System.out.println(map);
Dublicate key AA
{12=ASDFASDFASDF, 7=EEDDDAD, 4=CCCC, 3=BBB, 2=AA}
Can you guide me how can I sort Array List having Hash Map alphabatically?
JSONArray jArr2 = new JSONArray(jsonString2);
for(int i=0;i<jArr2.length();i++){
HashMap<String, String> map = new HashMap<String, String>();
map.put("titleName",jArr2.getJSONObject(i).getString("titleName"))
programList.add(map);
}
Implement a Comparator<HashMap<String, String>> which just extracts the value assocated with the value key, then use Collections.sort method to sort your arraylist.
For e.g.:
class MyComparator implements Comparator<Map<String, String>>{
private final String key;
public MyComparator(String key)
{
this.key = key;
}
public int compare(Map<String, String> first,
Map<String, String> second)
{
// TODO: Null checking, both for maps and values
String firstValue = first.get(key);
String secondValue = second.get(key);
return firstValue.compareTo(secondValue);
}
}
Looking at your example, I don't think you need a Map to be involved at all. What you have is a list of Maps, where every Map only has one key, which is "titleName". Why not just have a list of titlenames? Then your code would look like this:
JSONArray jArr2 = new JSONArray(jsonString2);
List<String> titleNames = new ArrayList<>();
for (int i = 0; i < jArr2.length(); i++) {
titleNames.add(jArr2.getJSONObject(i).getString("titleName"))
}
You know that the list only contains titleNames, you don't need to complicate the data structure with Maps!
Then you can sort the list simply by using
Collections.sort(titleNames);
Note that this will work while the other answers that suggests Collections.sort() on the list of maps will not work. This is because titleNamees is a List of Strings, which implement Comparable (ie the sort() method knows how to order them with respect to each other), while Map does not implement comparable (as there are multiple ways to order Maps - number of entries, total number of bytes, etc).
Yes you can use Collections.sort(); with a custom comparator. Here is the doc.
Collections.sort(YOUR_ARRAY_LIST, new YourCustomComparator());
And this should be the class you must have
class YourCustomComparator implements Comparator<HashMap<String, String>> {
#Override
public int compare(HashMap<String, String> lhs, HashMap<String, String> rhs) {
// check here your objects. lhs and rhs. compare them as you want
// return 1 if lhs is greater than rhs
// return 0 if ther are same
// return -1 otherwise
}
}
I have a
TreeMap resMap new TreeMap<String, Map<String, String>>();
I would like to filter and keep only entries that values contains a known pair, let's say ('mike' => 'jordan'), and avoid a loop like below
Is there in my included libraries apache.commons and google.common a filter method (that probably would do a loop too, but at least it's less verbose
for (Entry<String, TreeMap<String, String>> el : resMap.entrySet()){
if (el.getValue().get("mike").equals("jordan")){
//
}
}
You can use filters from Guava and the Predicate interface.
Predicate<T> yourFilter = new Predicate<T>() {
public boolean apply(T o) {
// your filter
}
};
So, simple example would be:
Predicate<Integer> evenFilter = new Predicate<Integer>() {
public boolean apply(Integer i) {
return (i % 2 == 0);
}
};
Map<Integer, Integer> map = new HashMap<Integer, Integer>();
Map<Integer, Integer> evenMap = Maps.filterValues(map, evenFilter);
Rather than force your client code to use a filter/loop, build what you need into the API of your class:
public class MyClass {
private TreeMap resMap new TreeMap<String, Map<String, String>>();
public void filter(String key, String value) {
// Some impl here. Either your loop or the guava approach
}
}
BTW, if you use your loop, consider changing to this:
for (Iterator<Map.Entry<String, TreeMap<String, String>>> i = resMap.entrySet().iterator(); i.hasNext();) {
Map.Entry<String, TreeMap<String, String>> entry = i.next();
if (value.equals(entry.getValue().get(key))) {
i.remove();
}
}
The changes to the loop are:
Changed order of equals to avoid NPE
Using iterator to allow removal of entries directly
Even if you don't have a class, you could easily wrap it up in a static method on a utility class, where it could also easily be parameterized to work with any nested map:
public static <K1, K2, V> void filter(Map<K1, Map<K2, V>> map, K2 key, V value) {
// Some impl here
}
Here's a non-guava impl for the static method:
for (Iterator<Map.Entry<K1, Map<K2, V>>> i = map.entrySet().iterator(); i.hasNext();) {
Map.Entry<K1, Map<K2, V>> entry = i.next();
if (value.equals(entry.getValue().get(key))) {
i.remove();
}
}
From #Ferrybig answer in this post.
You can use the Java 8 method Collection.removeIf for this purpose:
map.values().removeIf(Object o -> o.get("mike").equals("jordan"));
This removed all values that match the predicate.
Online demo
This works by the fact that calling .values() for a HashMap returns a collection that delegated modifications back to the HashMap itself, meaning that our call for removeIf() actually changes the HashMap (this doesn't work on all java Map's)
Take a look at Guava's Predicates and Functions.
Here are two examples. The both print the key based on match in the value's properties.
private static void printMatchingEntriesUsingALoop(Map<String, Map<String, String>> resMap, String key, String value) {
for (Map.Entry<String, Map<String, String>> entry : resMap.entrySet())
if (value.equals(entry.getValue().get(key)))
System.out.println(entry.getKey());
}
private static void printMatchingEntriesUsingGuava(Map<String, Map<String, String>> resMap, final String key, final String value) {
Predicate<Map<String, String>> keyValueMatch =
new Predicate<Map<String, String>>() {
#Override
public boolean apply(#Nullable Map<String, String> stringStringMap) {
return value.equals(stringStringMap.get(key));
}
};
Maps.EntryTransformer<String, Map<String, String>, Void> printKeys =
new Maps.EntryTransformer<String, Map<String, String>, Void>() {
#Override
public Void transformEntry(#Nullable String s,
#Nullable Map<String, String> stringStringMap) {
System.out.println(s);
return null;
}
};
Maps.transformEntries(Maps.filterValues(resMap, keyValueMatch), printKeys);
}
public static void main(String... args) {
Map<String, Map<String, String>> resMap = new TreeMap<String, Map<String, String>>();
printMatchingEntriesUsingALoop(resMap, "first", "mike");
printMatchingEntriesUsingGuava(resMap, "first", "mike");
}
One uses a loop and one use Guava.
While the first one performs better, you should really decide which will be the easiest to understand and maintain.
Some suggestions from #missingfaktor. You have to use your own judgement, but he highlighted some of the issues well.
a lot of code duplication.
special case handling.
More cyclomatic complexity.
More chances of error, as a result of first three bullets.
Hard to follow code.
Imagine you are a new developer who has to support this software. Which would you rather be facing?
You can filter the map using java 8 and streams. The first step in this process is converting to a stream using entrySet().stream(). This gives you a Stream<Map.Entry<String, TreeMap<String, String>>. You can then use filter(...) to filter the list. When you filter, you should return true when the incoming value should be included in the filter result. After you filtered the results, you can use foreach to loop over the final result.
The final result will look like the following:
resMap.entrySet().stream()
.filter(e -> el.getValue().get("mike").equals("jordan"))
.foreach(e -> {
// Do something with your entry here
});
I want to group elements of a list. I'm currently doing it this way:
public static <E> List<List<E>> group(final List<E> list, final GroupFunction<E> groupFunction) {
List<List<E>> result = Lists.newArrayList();
for (final E element : list) {
boolean groupFound = false;
for (final List<E> group : result) {
if (groupFunction.sameGroup(element, group.get(0))) {
group.add(element);
groupFound = true;
break;
}
}
if (! groupFound) {
List<E> newGroup = Lists.newArrayList();
newGroup.add(element);
result.add(newGroup);
}
}
return result;
}
public interface GroupFunction<E> {
public boolean sameGroup(final E element1, final E element2);
}
Is there a better way to do this, preferably by using guava?
Sure it is possible, and even easier with Guava :) Use Multimaps.index(Iterable, Function):
ImmutableListMultimap<E, E> indexed = Multimaps.index(list, groupFunction);
If you give concrete use case it would be easier to show it in action.
Example from docs:
List<String> badGuys =
Arrays.asList("Inky", "Blinky", "Pinky", "Pinky", "Clyde");
Function<String, Integer> stringLengthFunction = ...;
Multimap<Integer, String> index =
Multimaps.index(badGuys, stringLengthFunction);
System.out.println(index);
prints
{4=[Inky], 6=[Blinky], 5=[Pinky, Pinky, Clyde]}
In your case if GroupFunction is defined as:
GroupFunction<String> groupFunction = new GroupFunction<String>() {
#Override public String sameGroup(final String s1, final String s2) {
return s1.length().equals(s2.length());
}
}
then it would translate to:
Function<String, Integer> stringLengthFunction = new Function<String, Integer>() {
#Override public Integer apply(final String s) {
return s.length();
}
}
which is possible stringLengthFunction implementation used in Guava's example.
Finally, in Java 8, whole snippet could be even simpler, as lambas and method references are concise enough to be inlined:
ImmutableListMultimap<E, E> indexed = Multimaps.index(list, String::length);
For pure Java 8 (no Guava) example using Collector.groupingBy see Jeffrey Bosboom's answer, although there are few differences in that approach:
it doesn't return ImmutableListMultimap but rather Map with Collection values,
There are no guarantees on the type, mutability, serializability, or thread-safety of the Map returned (source),
it's a bit more verbose than Guava + method reference.
EDIT: If you don't care about indexed keys you can fetch grouped values:
List<List<E>> grouped = Lists.transform(indexed.keySet().asList(), new Function<E, List<E>>() {
#Override public List<E> apply(E key) {
return indexed.get(key);
}
});
// or the same view, but with Java 8 lambdas:
List<List<E>> grouped = Lists.transform(indexed.keySet().asList(), indexed::get);
what gives you Lists<List<E>> view which contents can be easily copied to ArrayList or just used as is, as you wanted in first place. Also note that indexed.get(key) is ImmutableList.
// bonus: similar as above, but not a view, instead collecting to list using streams:
List<List<E>> grouped = indexed.keySet().stream()
.map(indexed::get)
.collect(Collectors.toList());
EDIT 2: As Petr Gladkikh mentions in comment below, if Collection<List<E>> is enough, above example could be simpler:
Collection<List<E>> grouped = indexed.asMap().values();
Collector.groupingBy from the Java 8 streams library provides the same functionality as Guava's Multimaps.index. Here's the example in Xaerxess's answer, rewritten to use Java 8 streams:
List<String> badGuys = Arrays.asList("Inky", "Blinky", "Pinky", "Pinky", "Clyde");
Map<Integer, List<String>> index = badGuys.stream()
.collect(Collectors.groupingBy(String::length));
System.out.println(index);
This will print
{4=[Inky], 5=[Pinky, Pinky, Clyde], 6=[Blinky]}
If you want to combine the values with the same key in some other way than creating a list, you can use the overload of groupingBy that takes another collector. This example concatenates the strings with a delimiter:
Map<Integer, String> index = badGuys.stream()
.collect(Collectors.groupingBy(String::length, Collectors.joining(" and ")));
This will print
{4=Inky, 5=Pinky and Pinky and Clyde, 6=Blinky}
If you have a large list or your grouping function is expensive, you can go parallel using parallelStream and a concurrent collector.
Map<Integer, List<String>> index = badGuys.parallelStream()
.collect(Collectors.groupingByConcurrent(String::length));
This may print (the order is no longer deterministic)
{4=[Inky], 5=[Pinky, Clyde, Pinky], 6=[Blinky]}
The easiest and simplest way would be using: Lamdaj grouping feature
The above example can be re-written:
List<String> badGuys = Arrays.asList("Inky", "Blinky", "Pinky", "Pinky", "Clyde");
Group group = group(badGuys, by(on(String.class).length)));
System.out.println(group.keySet());
With Java 8, Guava and few helper functions you can implement grouping with custom Comparator
public static <T> Map<T, List<T>> group(List<T> items, Comparator<T> comparator)
{
ListMultimap<T, T> blocks = LinkedListMultimap.create();
if (!ArrayUtils.isNullOrEmpty(items))
{
T currentItem = null;
for (T item : items)
{
if (currentItem == null || comparator.compare(currentItem, item) != 0)
{
currentItem = item;
}
blocks.put(currentItem, ObjectUtils.clone(item));
}
}
return Multimaps.asMap(blocks);
}
Example
Comparator<SportExercise> comparator = Comparator.comparingInt(SportExercise::getEstimatedTime)
.thenComparingInt(SportExercise::getActiveTime).thenComparingInt(SportExercise::getIntervalCount)
.thenComparingLong(SportExercise::getExerciseId);
Map<SportExercise, List<SportExercise>> blocks = group(sportWorkout.getTrainingExercises(), comparator);
blocks.forEach((key, values) -> {
System.out.println(key);
System.out.println(values);
});
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?
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.
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.
With lambdaj you just need one line of code to achieve that result as it follows:
group(values, by(on(CategoryValuePair.class).getCategory()));
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;
}