1

I need to enter key-value pairs into a data structure that allows me to retrieve them in ascending order of the key--BUT their may be many keys of the same value.

Thus, if the kv-pairs were {10-a, 10-b, 9-c, 8-d, 8-e, 8-f, 4-g, 4-h, 2-i} I would need to retrieve the values in the order: a, b ,c, d, e, f, g, h, i. Are there any data structures in the JAVA API that supports this?

I tried using a TreeMap because it kept them in order which allowed me to use TreeMap.lastKey() to retrieve the highest current key, but I didn't know that it overwrote any duplicate keys that were already in the map. I need something that doesn't overwrite (similar to a HASH), but also allows me to retrieve them in a sorted order--does this exist?

Thank you!

2
  • So a single Map with a List of values would correlate to one Key with multiple Values--I believe I can store the Maps in an ArrayList, correct? Commented Mar 3, 2013 at 5:46
  • 1
    A HashMap also overwrites duplicate keys. I suspect that's not what you really mean? Also, you say ascending order of keys, but your example is in descending order? Did you mean descending order of keys and ascending order of values? Commented Mar 3, 2013 at 5:46

2 Answers 2

1

Unfortunately you probably will not find a structure that supports multiple values of the same keys. As Dilum said, there are several implementations of "MultiMap" or "Multi-Valued Maps" that would work well.

In addition to Guava's TreeMultiMap, there's also the Spring Framework's MultiValueMap and Apache Common's MultiValueMap.

An example of the Spring implementation would be:

import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;


public class MultiValueMapExample {

    public static void main(String[] args) {
        // 10-a, 10-b, 9-c, 8-d, 8-e, 8-f, 4-g, 4-h, 2-i
        MultiValueMap<Integer, String> map = new LinkedMultiValueMap<Integer, String>();
        map.add(10, "a");
        map.add(10, "b");
        map.add(9, "c");
        map.add(8, "d");
        map.add(8, "e");
        map.add(8, "f");
        map.add(8, "g");
        map.add(4, "h");
        map.add(2, "i");

        System.out.println(map.toString());
        // {10=[a, b], 9=[c], 8=[d, e, f, g], 4=[h], 2=[i]}
    }
}

You could use this by adding Spring-Core via the following Maven dependency:

<dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>3.1.1.RELEASE</version>
        </dependency>

If you need help getting any of these libs in your project, feel free to comment / contact me.

Update 1

Turns out there's not a convenient way to filter / sort from the raw API's. I've included a simple filter function below that should do the trick.

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;


public class MultiValueMapExample {

    public static void main(String[] args) {
        // 10-a, 10-b, 9-c, 8-d, 8-e, 8-f, 4-g, 4-h, 2-i
        MultiValueMap<Integer, String> map = new LinkedMultiValueMap<Integer, String>();
        map.add(8, "g");
        map.add(4, "h");
        map.add(10, "a");
        map.add(10, "b");
        map.add(9, "c");
        map.add(8, "d");
        map.add(8, "e");
        map.add(8, "f");

        map.add(2, "i");

        System.out.println(map.toString());
        // {8=[g, d, e, f], 4=[h], 10=[a, b], 9=[c], 2=[i]}

        MultiValueMap<Integer, String> filteredMap = filter(5, map);
        System.out.println( filteredMap.toString() );
        // {10=[a, b], 9=[c], 8=[g, d, e, f], 4=[h], 2=[i]}

    }

    public static MultiValueMap<Integer, String> filter(int numberOfResults, MultiValueMap<Integer, String> map){
        MultiValueMap<Integer, String> result = new LinkedMultiValueMap<Integer, String>();

        List<Integer> keys = new ArrayList<Integer>(map.keySet());
        Collections.sort(keys, Collections.reverseOrder());

        for(Integer key : keys){
            if( result.size() <= numberOfResults ){
                result.put(key, map.get(key));
            }else{
                break;
            }
        }

        return result;

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

4 Comments

David, would it be possible to retrive the items in the multiset in order of the keys? For example, I have an array of size 5 and I want to take the values with the 5 highest keys. In this case, I would take a, b, c, d, and e. Is this possible in any of the implementations? If so, I'd be very interested in your help in getting the library into my project, thanks!
Yeah, you should be able to by using Collections.sort with a comparable implementation. Do you want to do it based on highest key value or the key with the most values?
Turns out filtering maps is a bit trickier. I added an updated example with a simple filtering method. It should work well enough, unless you have a large dataset or something
@kpscript did any of the answers help you out? If so, please vote :D
1

The term that is usually used in Java is 'MultiMap'. For example, look at Guava's TreeMultiMap

Neither the interface nor any implementation is part of that standard APIs.

Comments

Your Answer

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