Leo
Leo

Reputation: 5235

Sorting map based on list values

I have a map like below:

Map<String, String> map1 = new HashMap<String, String>();

and the contents are:

ID_1 -> ID_2
------------
100 -> 10
200 -> 20
300 -> 30

Based on the value of ID_2 I have to query an oracle table and get a code value corresponding to each entry:

ID_1 -> ID_2 -> code
--------------------
100 -> 10 -> 8
200 -> 20 -> 2
300 -> 30 -> 9

and then I will have to get the map1 sorted in ascending way by the code value i.e the result should be:

200 -> 20
100 -> 10
300 -> 30

I have thought of creating an intermediary map with <ID_1, List<ID_2,code>> as <K,V> and then sort using the code value and then get the final output.

Is there any shorter way to do so, like without using an intermediary map?

Upvotes: 0

Views: 86

Answers (4)

Saravana
Saravana

Reputation: 12817

With Java streams you can achieve this without using any additional collections, here is an implementation.

To maintain order have used LinkedHashMap in the collector

For simplicity I have taken one more map to hold the db values [you need to change this to get from DB]

    Map<String, String> map1 = new HashMap<String, String>();
    map1.put("100", "10");
    map1.put("200", "20");
    map1.put("300", "30");

    Map<String, String> dbmap = new HashMap<String, String>();
    dbmap.put("10", "8");
    dbmap.put("20", "2");
    dbmap.put("30", "9");

    Comparator<String> comp = (k1, k2) -> dbmap.get(map1.get(k1)).compareTo(dbmap.get(map1.get(k2)));

    Map<String, String> queryMap = map1.keySet().stream().sorted(comp)
            .collect(toMap((String key) -> key, value -> (String) map1.get(value), (u, v) -> {
                throw new IllegalStateException(String.format("Duplicate key %s", u));
            }, LinkedHashMap::new));

    System.out.println(queryMap);

Ouput

{200=20, 100=10, 300=30}

Upvotes: 0

GPI
GPI

Reputation: 9308

I would express you logic as follow :

  1. Get all entries in the map
  2. Affect to each one its score (through the database call)
  3. Order the entries in a final map according to step 2

It is important to notice that few maps have ordering constraints. The base implementation that comes to mind is LinkedHashMap. Furthermore "reordering an existing map" seems like a strange idea that is not backed by any methods in the Map interface. So in a nutshell, saying you need to return a Map that has an ordering constraint seems like a bad/incomplete idea - but it is certainly doable.

I would also adivse against using a TreeMap which is a Map ordered by a Comparator because I see no constraint that your ordering values are unique. Plus, your ordering is on the values, not the keys, of the map. Such a comparator would not be straightforward at all.

So, in short, what I would do is

    LinkedHashMap<String, String> sorted = map.entrySet().stream()
        // This is your DB call
        .sorted(Comparator.comparing(entry -> getDBValue(entry)))
        // Now we have an ordered stream of key/value entries from the original map
        .collect(
            // We flush back to a Map
            Collectors.toMap(
                    // Keeping the original keys as is
                    Map.Entry::getKey, 
                    // Keeping the original values as is
                    Map.Entry::getValue, 
                    // This merge step should never be called, as keys are unique. Maybe you could assert that and fail if this is called
                    (v1, v2) -> v1,
                    // This is where you instanciate the Map that respects ordering of keys. Here, LinkedHashMap is iterable in the order of insertion, which is what we want.
                    LinkedHashMap::new
                  )
    );

Upvotes: 0

Bahramdun Adil
Bahramdun Adil

Reputation: 6079

You try this code below: I used int[] array instead of List

public class Test {

    public static void main(String[] args) throws Exception {
        Map<String, int[]> map = new HashMap<>();
        map.put("100", new int[]{10, 8});
        map.put("200", new int[]{20, 2});
        map.put("300", new int[]{30, 9});

        Map<String, int[]> sortByValue = sortByValue(map);
        for (Map.Entry<String, int[]> entry : sortByValue.entrySet()) {
            System.out.println(entry.getKey() +" -> "+ entry.getValue()[0]);
        }

    }

    private static Map<String, int[]> sortByValue( Map<String, int[]> map ) {
        List<Map.Entry<String, int[]>> list = new LinkedList<>(map.entrySet());
        Collections.sort(list, (o1, o2) -> Integer.compare(o1.getValue()[1], o2.getValue()[1]));
        Map<String, int[]> result = new LinkedHashMap<>();
        for (Map.Entry<String, int[]> entry : list) {
            result.put(entry.getKey(), entry.getValue());
        }
        return result;
    }
}

And it is the result:

200 -> 20
100 -> 10
300 -> 30

Upvotes: 1

Natalia
Natalia

Reputation: 4532

Based on map1 you can build new map:

 Map<String, Pair<String, String> map2

where key is id from oracle db.

As you need to have ordering you can use TreeMap and method

Map.Entry<K,V> firstEntry();

Upvotes: 0

Related Questions