简体   繁体   中英

Sorting LinkedHashMap<String, String[]>.entrySet() by the keys, but in the middle of the keys using a regex

I have a LinkedHashMap which maps strings to string arrays.

The keys have the format of something like this: " xxx (yyy(0.123)) "

Basically, I want to be able to sort the entry set in such a way that it sorts it by the decimal part, and not the beginning of the string. What I have done so far is converting the entry set to an ArrayList so that I can try calling Arrays.sort on it, but obviously that's going to just sort by the beginning of the string.

What I'm currently thinking is that I would have to go through this array, convert each key in the pair to a custom class with a comparator that compares the way I want it to (with the regular expression .*\\((.*)\\)\\) to find the decimal). However, that sounds like a bunch of unnecessary overhead, so I was wondering if there was a simpler way. Thanks in advance.

Your solution sounds fine.

If you run into performance issues, you could look buffering the decimal value by replacing your strings with an object that contains the string and the decimal value. Then it does not need to be recalculated multiple times during the sort.

There are trade offs for the buffered solution as above and figuring out which technique is optimal will really depend on your entire solution.

Is there a reason you need to use LinkedHashMap ? The javadoc specifically states

This linked list defines the iteration ordering, which is normally the order in which keys were inserted into the map (insertion-order)

TreeMap seems a better fit for what you're trying to achieve, which allows you to provide a Comparator at construction. Using Java 8, this could be achieved with something like:

private static final String DOUBLE_REGEX = "(?<value>\\d+(?:\\.\\d+)?)";
private static final String FIND_REGEX = "[^\\d]*\\(" + DOUBLE_REGEX + "\\)[^\\d]*";
private static final Pattern FIND_PATTERN = Pattern.compile(FIND_REGEX);

private static final Comparator<String> COMPARATOR = Comparator.comparingDouble(
    s -> {
        final Matcher matcher = FIND_PATTERN.matcher(s);
        if (!matcher.find()) {
            throw new IllegalArgumentException("Cannot compare key: " + s);
        }
        return Double.parseDouble(matcher.group("value"));
    });

private final Map<String, List<String>> map = new TreeMap<>(COMPARATOR);

Edit: If it has to be a LinkedHashMap ( yours ), you can always:

map.putAll(yours);
yours.clear();
yours.putAll(map);

First, you cannot "sort" a LinkedHashMap . LinkedHashMap maintain the iteration order based on the order of insertion.

If you means creating another LinkedHashMap by inserting using values from the original map, with order based on sorted order: You need to be aware of any new entries added after your initial construction will be unsorted. So you may want to create an unmodifiable Map.

For the Comparator implementation, you do not need to make it to your custom class. Just create a comparator that do the comparison is good enough.

Like this:

(haven't compiled, just to show you the idea)

// assume the key is in format of "ABCDE,12345", and you want to sort by the numeric part:
Map<String, Foo> oldMap = ....; // assume you populated something in it
Map<String, Foo> sortedMap 
    = new TreeMap((a,b) -> {
                     // here I use split(), you can use regex
                     int aNum = Integer.valueOf(a.split(",")[1]);
                     int bNum = Integer.valueOf(b.split(",")[1]);
                     if (aNum != bNum )  {
                         return aNum - bNum;
                     } else {
                         return a.compareTo(b);
                     });
sortedMap.addAll(oldMap);
// now sortedMap contains your entries in sorted order.
// you may construct a new LinkedHashMap with it or do whatever you want

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM