Home > Back-end >  Sorting a List where the list entries is a string but need the substring to trigger on
Sorting a List where the list entries is a string but need the substring to trigger on

Time:07-29

I have a List<String> skuList = new ArrayList<>(); which gets loaded from Firebase Realtime DB.

The following is what gets loaded:

com.replaysport.pickempartyapp.20
com.replaysport.pickempartyapp.12
com.replaysport.pickempartyapp.75
com.replaysport.pickempartyapp.30
com.replaysport.pickempartyapp.5
com.replaysport.pickempartyapp.100
com.replaysport.pickempartyapp.50

I would like it to get sorted by the integer value after the last '.' but i am just not able to figure it out!?

I have tried the Collections.sort(skuList) which sorts it by the String value and puts the 100 at the beginning and 5 and 50 at the end, where 5 should be first and 100 should be last in the order i am looking for.

CodePudding user response:

Try this: Kotlin:

list.sortedBy {
    it.split(".").last().toInt()
}

Java:

private int extractNum(String s) {
        String[] splits = s.split(".");
        int lastSplitIndex = splits.length - 1;
        return Integer.valueOf(splits[lastSplitIndex]);
    }

List<String> getSortedList(ArrayList<String> inputList) {
        return inputList.stream().sorted(
                new Comparator<String>() {
                    @Override
                    public int compare(String s1, String s2) {
                        return Integer.compare(extractNum(s1), extractNum(s2));
                    }
                }
        ).collect(Collectors.toList());
    }

CodePudding user response:

Instead of calling Collections.sort(list), you need to provide a comparator that defines how the values should be compared. Without providing a comparator, sort() will use the natural ordering for the objects, which is java.lang.String.

Here's a starting point to create a list and add three values (picked from your original post):

List<String> list = new ArrayList<>();
list.add("com.replaysport.pickempartyapp.5");
list.add("com.replaysport.pickempartyapp.100");
list.add("com.replaysport.pickempartyapp.50");

Here's an example showing how sort(list) doesn't produce results you want - first is 100, then 5, then 50:

Collections.sort(list);
System.out.println(list);

[com.replaysport.pickempartyapp.100, com.replaysport.pickempartyapp.5, com.replaysport.pickempartyapp.50]

Here's an example showing how you could create a comparator that does what you want – look for the last occurrence of ".", get a substring from that point on, treat those things as Integers, then use the default comparison for Integer. In the output below, you can see that the ordering is now 5, 50, and 100.

list.sort((o1, o2) -> {
    Integer number1 = Integer.parseInt(o1.substring(o1.lastIndexOf('.')   1));
    Integer number2 = Integer.parseInt(o2.substring(o2.lastIndexOf('.')   1));
    return number1.compareTo(number2);
});
System.out.println(list);

[com.replaysport.pickempartyapp.5, com.replaysport.pickempartyapp.50, com.replaysport.pickempartyapp.100]

Note that this is meant to be a functioning example for you. You'll need to look more closely at the right comparator implementation for you, and include any guards or checks if the data does not conform the way you expect (handle edge cases).

Also, it might be possible to expolore whether it's necessary for each list item to start with "com.replaysport.pickempartyapp." – if they're all the same, perhaps you could chop that part off at the start, and change the list type from List<String> to List<Integer>. If you could do that, you could go back to list.sort() and skip the custom comparator.

CodePudding user response:

This should work

skuList.sort((s1, s2) -> {
   final String s1Postfix = s1.substring(s1.lastIndexOf('.')   1);
   final String s2Postfix = s2.substring(s2.lastIndexOf('.')   1);
   return Integer.valueOf(s1Postfix).compareTo(Integer.valueOf(s2Postfix));
});
  • Related