Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How sort an arraylist of names in alphabetical order but names which start with numbers must comes last

i need to sort names list in to alphabetical order, for this i use the interfase comperator for sorting the names

  @Override
    public int compareTo(ContactModel another) {
        // TODO Auto-generated method stub
        return getname().compareTo(another.getname());
    }

Suppose this is my array of name

123vinish
23Sathya
24mahesh
Ranjith
Vipin
Bibin
Shine
Thomas

i need to sort this in a sequence where names with numbers must come last

Bibin
Ranjith
Shine
Thomas
Vipin
123Vinish
23Sathya
24mahesh

How can we implement this

like image 474
ranjith Avatar asked Feb 13 '23 10:02

ranjith


1 Answers

String.compareTo(String) sort the Strings by the ascii value of the characters. You need to change the comparator. Example with a custom comparator:

List<String> al = new ArrayList<String>();
al.add("123vinish");
al.add("23Sathya");
al.add("24mahesh");
al.add("Ranjith");
al.add("Vipin");
al.add("Bibin");
al.add("Shine");
al.add("Thomas");

Comparator<String> nameComparator  = new Comparator<String>() 
{
    @Override
    public int compare(String value1, String value2)
    {
        if(Character.isDigit(value1.charAt(0))&&!Character.isDigit(value2.charAt(0)))
            return 1;
        if(Character.isDigit(value2.charAt(0))&&!Character.isDigit(value1.charAt(0)))
            return -1;
        return value1.compareTo(value2);
    }
};

Collections.sort(al, nameComparator);

System.out.println(al);

Output: [Bibin, Ranjith, Shine, Thomas, Vipin, 123vinish, 23Sathya, 24mahesh]

And if you want to override the compareTo method in the class where you implemented the Comparable<> interface, it have to look like this:

    @Override
    public int compareTo(ContactModel anotherValue)
    {
        if(Character.isDigit(this.getname().charAt(0))&&!Character.isDigit(anotherValue.getname().charAt(0)))
            return 1;
        if(Character.isDigit(anotherValue.getname().charAt(0))&&!Character.isDigit(this.getname().charAt(0)))
            return -1;
        return this.getname().compareTo(anotherValue.getname());
    }

EDIT: If you want that a String like 2a appear before something like 23 then you only have to loop over every character in the String. Then the custom comparator have to look like this:

Comparator<String> nameComparator  = new Comparator<String>() 
{
    @Override
    public int compare(String value1, String value2)
    {
        for(int i = 0; i < Math.min(value1.length(), value2.length()); i++)
        {
            //value1 is digit and value2 is not
            if(Character.isDigit(value1.charAt(i)) && !Character.isDigit(value2.charAt(i)))
                return 1;
            //value2 is digit and value1 is not
            else if(Character.isDigit(value2.charAt(i)) && !Character.isDigit(value1.charAt(i)))
                return -1;
            //both are digits with different size
            else if(Character.isDigit(value1.charAt(i)) && Character.isDigit(value2.charAt(i)) && Integer.valueOf(value1.charAt(i))!=Integer.valueOf(value2.charAt(i)))
                return value1.compareTo(value2);
            //both are no digits
            else if(!Character.isDigit(value1.charAt(i)) && !Character.isDigit(value2.charAt(i)))   
                return value1.compareTo(value2);
            //loop again if they are both digits with the same value
        }
        return value1.compareTo(value2);
    }
};

EDIT 2:

I have creat another solution for your problem. I've copied the implementation of the compareTo method in String class and modified the ascii values of numbers while the comparing. This example can be used in your ContactModel class.

@Override
public int compareTo(ContactModel anotherValue) {
    int len1 = this.getname().length();
    int len2 = anotherValue.getname().length();
    int lim = Math.min(len1, len2);
    char v1[] = this.getname().toCharArray();
    char v2[] = anotherValue.getname().toCharArray();

    int k = 0;
    while (k < lim) {
        //Do the trick here! If char is a digit, add 75.
        char c1 = Character.isDigit(v1[k]) ? ((char)(v1[k]+75)) : v1[k];  
        char c2 = Character.isDigit(v2[k]) ? ((char)(v2[k]+75)) : v2[k];
        if (c1 != c2) {
            return c1 - c2;
        }
        k++;
    }
    return len1 - len2;
}
like image 89
kai Avatar answered Feb 16 '23 04:02

kai