Search code examples
javacomparable

Java Sort algorithm String with Number


I have a List of Strings. EXAMPLE_1, EXAMPLE_2, EXAMPLE_3 ... EXAMPLE_99 What is the best algorithm for sorting here?

Is it possible with a Collator? This is my current procedure, but I guess there could be a better way:

public class Example implements Comparable<Example> {
    private final String id;

    public getId() {
        return id;
    }

    private Integer getIdNo() {
        try {
            return Integer.parseInt(getId().replaceAll("[\\D]", ""));
        } catch (NumberFormatException e) {
            return null;
        }
    }

    @Override
    public int compareTo(Example o) {
        if ((getIdNo() == null && getIdNo() != null) || (getProductFeatureId_sizeNo() < o.getProductFeatureId_sizeNo())) {
            return -1;
        } else if (o.getIdNo() == null || getIdNo() > o.getIdNo()) {
            return 1;
        }

        return 0;
    }
}

Solution

  • This is better alternative - AlphanumComparator.java

    Copying the code for ready reference -

    public class AlphanumComparator implements Comparator
    {
        private final boolean isDigit(char ch)
        {
            return ch >= 48 && ch <= 57;
        }
    
        /** Length of string is passed in for improved efficiency (only need to calculate it once) **/
        private final String getChunk(String s, int slength, int marker)
        {
            StringBuilder chunk = new StringBuilder();
            char c = s.charAt(marker);
            chunk.append(c);
            marker++;
            if (isDigit(c))
            {
                while (marker < slength)
                {
                    c = s.charAt(marker);
                    if (!isDigit(c))
                        break;
                    chunk.append(c);
                    marker++;
                }
            } else
            {
                while (marker < slength)
                {
                    c = s.charAt(marker);
                    if (isDigit(c))
                        break;
                    chunk.append(c);
                    marker++;
                }
            }
            return chunk.toString();
        }
    
        public int compare(Object o1, Object o2)
        {
            if (!(o1 instanceof String) || !(o2 instanceof String))
            {
                return 0;
            }
            String s1 = (String)o1;
            String s2 = (String)o2;
    
            int thisMarker = 0;
            int thatMarker = 0;
            int s1Length = s1.length();
            int s2Length = s2.length();
    
            while (thisMarker < s1Length && thatMarker < s2Length)
            {
                String thisChunk = getChunk(s1, s1Length, thisMarker);
                thisMarker += thisChunk.length();
    
                String thatChunk = getChunk(s2, s2Length, thatMarker);
                thatMarker += thatChunk.length();
    
                // If both chunks contain numeric characters, sort them numerically
                int result = 0;
                if (isDigit(thisChunk.charAt(0)) && isDigit(thatChunk.charAt(0)))
                {
                    // Simple chunk comparison by length.
                    int thisChunkLength = thisChunk.length();
                    result = thisChunkLength - thatChunk.length();
                    // If equal, the first different number counts
                    if (result == 0)
                    {
                        for (int i = 0; i < thisChunkLength; i++)
                        {
                            result = thisChunk.charAt(i) - thatChunk.charAt(i);
                            if (result != 0)
                            {
                                return result;
                            }
                        }
                    }
                } else
                {
                    result = thisChunk.compareTo(thatChunk);
                }
    
                if (result != 0)
                    return result;
            }
    
            return s1Length - s2Length;
        }
    }
    

    Note: you should generify this class if you're using java 1.5+