Search code examples
javaspring-bootsortingsubstringbackend

Sorting a list of objects by an attribute's substring


I have a list of objects containing an attribute date that looks like this "Thu Oct 26 2023"

I want to sort those objects by their substring(8,9) which is 26 in this case.

I've looked up parsing the substring to int and using a Comparator and then Collections.sort but I am wondering if there is a better way to do this.


Solution

  • I want to sort those objects by their substring(8,9) which is 26 in this case.

    substring(8, 9) will not provide 26 from "Thu Oct 26 2023", it will provide 2. To get 26 you would need substring(8, 10). At this stage, it's hard to say whether or not the days of the month will always be in the format of two digits (as in 01, 02, 30, etc) or will it possibly be in the format of single digits as well (as in 1, 2, 30, etc).

    In the provided date ("Thu Oct 26 2023"), one thing that is for sure is the fact that, if the actual string date format is always followed, there will always be a white-space between the date components. Based on this fact, it would be more beneficial to split the date components to collect the actual day of the month regardless of how many digits it may be.

    // `hireDate` is an instance variable within the `MyObject` class:
    // `list` is a List of MyObject instances, ex: List<MyObject> list = new ArrayList<>();
    list.sort(java.util.Comparator.comparing(e -> e.hireDate.split("\\s")[2]));
    

    This however will not sort properly. Consider the fact that the date is a string and string represented integer numbers such as the day of month and the year do not sort the same as actual Integer (int or long type) numbers, for example, to sort string values of: "10", "3", "1", and "5", you would think that the sorted result would be: "1", "3", "5", "10" but...it won't be. It will be sorted as "1", "10", "3", "5". If the above values were actual int or long type integer values: 10, 3, 1, and 5 then these numbers would indeed be sorted in ascending order as 1, 3, 5, 10 as expected.

    To get around this little problem we can convert the String represented integer values to BigInteger which accepts string values and will allow the sort to be carried out properly:

    // `hireDate` is an instance variable within the `MyObject` class:
    // `list` is a List of MyObject instances, ex: List<MyObject> list = new ArrayList<>();
    list.sort(java.util.Comparator.comparing(e -> 
                new java.math.BigInteger(e.hireDate.split("\\s")[2])));
    

    would result in a sorted list of: "1", "3", "5", "10".

    To see the above code in action, create a new project and create a SortByDay class with a main() method and copy paste the following runnable code into it. Be sure to read the comments in code:

    public class SortByDay {
        
        public static void main(String[] args) {
            /* App started this way to avoid the need for statics
               unless we really want them:        */
            new SortByDay().startApp(args);
        }
        
        private void startApp(String[] args) {
            // Create a java.util.List of MyObject instances:
            java.util.List<MyObject> objList = new java.util.ArrayList<>();
            objList.add(new MyObject("Tom Jones", 66, "Thu Oct 4 2023", 32.50));
            objList.add(new MyObject("Tracey Johnson", 59, "Tue Oct 10 2023", 31.00));
            objList.add(new MyObject("Dave Simpson", 30, "Wed Oct 1 2023", 43.75));
            
            /* Display the List before sorting in Ascending order
               by day of month:            */
            System.out.println("Before Sorting:\n===============");
            for (MyObject o : objList) {
                System.out.println(o.toString());
            }
            System.out.println();
            
            /* Sort the List of MyObject based on the day of month 
               in each instance contained within the List:     */
            sortListedObjectByDayOfMonth(objList);
            
            /* Display the List after sorting in Ascending order
               by day of month:            */
            System.out.println("After Sorting:\n==============");
            for (MyObject o : objList) {
                System.out.println(o.toString());
            }
        }
        
        public void sortListedObjectByDayOfMonth(java.util.List<MyObject> list) {
            list.sort(java.util.Comparator.comparing(e -> 
                    new java.math.BigInteger(e.hireDate.split("\\s")[2])));
        }
        
        public class MyObject {
            
            // Instance (member) variables:
            private String name;
            private int age;
            private String hireDate;
            private double wage;
    
            // Constructor:
            public MyObject(String name, int age, String hireDate, double wage) {
                this.name = name;
                this.age = age;
                this.hireDate = hireDate;
                this.wage = wage;
            }
            
            @Override
            public String toString() {
                return name + ", " + age + ", \"" + hireDate + "\", $" 
                                    + String.format("%.02f", wage);
            }
        }    
    }
    

    Console Window output should look something like this when the code is run:

    Before Sorting:
    ===============
    Tom Jones, 66, "Thu Oct 4 2023", $32.50
    Tracey Johnson, 59, "Tue Oct 10 2023", $31.00
    Dave Simpson, 30, "Wed Oct 1 2023", $43.75
    
    After Sorting:
    ==============
    Dave Simpson, 30, "Wed Oct 1 2023", $43.75
    Tom Jones, 66, "Thu Oct 4 2023", $32.50
    Tracey Johnson, 59, "Tue Oct 10 2023", $31.00