Search code examples
javalistgenericsabstractcomparable

Abstract Data Types, sorting objects by specific variable in a list


Alright here we go.

I made an ADT in form of a sortedArrayList, which has an add method looking like this:

public boolean addToArray(T i)
    {


            int insertPlace = 0;

                for(int j=0;j<size;j++)
                { 

                    if(i.compareTo(sortedArray[j])<0)
                    {
                        insertPlace =j;
                        j = size;
                    }
                }
                if(size>0)
                {


                        for(int w=size-1; w>=insertPlace;w--)
                        {
                                sortedArray[size]=sortedArray[w];
                        }
                        sortedArray[insertPlace]=i;
                }
                else
                {
                    sortedArray[0]=i;
                }
                size++;



        return true;    


}

Now, this works wonders for my sorted ADT when the input is Strings. However, instead of strings, I want to add objects to the list in shape of Persons, an object containing 4 variables(String Country, String name, int age, int CPR). I want the Person objects to be sorted in the list by age.

Here is the Person class with the compareTo method for sorting.

public class Person implements Comparable<Person>
{
    int cpr=200193;
    int age=21;
    String name="John Doe";
    String Country="Uzbekistan";


    public Person() {
        this.cpr=cpr;
        this.age=age;
    }
    public Person(String name, String Country,int cpr,int age) 
    {
        this.cpr=cpr;
        this.age=age;
        this.name=name;
        this.Country=Country;
    }


    @Override
    public String toString()
    {
        return "Person [Country= " + Country + ", Name:" + name + ", Cpr: "+cpr+ ", age: "+age+"]";
    }

    public int compareTo(Person p)
    {
        int before=-1;
        int after=1;
        int middle=0;


        if(this.age!=p.age)
        {
            if(this.age>p.age) 
            {
                return before;
            } 

            if(this.age<p.age)
            {
                return after;
            }
        }
        return middle;
    }

Now, the problem is that the objects get sorted, since do not appear in the same order I call them to the list. I just can't figure out how they are sorted and how to make the objects sorted by age in the list.

EDIT

p1.addToArray(new Person());
p1.addToArray(new Person("Pete","Germany",111111,86));
p1.addToArray(new Person("John","Denmark",123456,75));
p1.addToArray(new Person("Michael Jackson", "America",112345,49));

Output:

Item: Person [Country= America, Name:Michael Jackson, Cpr: 112345, age: 49]
Item: Person [Country= Uzbekistan, Name:John Doe, Cpr: 200193, age: 21]
Item: Person [Country= Germany, Name:Pete, Cpr: 111111, age: 86]
Item: Person [Country= Denmark, Name:John, Cpr: 123456, age: 75]

Solution

  • I don't think your sorting function works:

    My test:

    static void test() {
        addToArray("Zello");
        addToArray("Boby");
        addToArray("Amy");
        addToArray("Coco");
        addToArray("Boris");
        for(int i = 0; i < size; i++) {
            System.out.println(sortedArray[i]);
        }
    }
    

    Output:

    Amy
    Boris
    Boby
    Zello
    Coco
    

    Here is a different and more efficient way to do it.

    Use Arrays.binarySearch() to find the proper insertion position. Mind you, this function returns:

    • the index of the value if it already exists.
    • the -(insertPosition - 1) if the value doesn't exist.

    I assume based on your code that the size variable represents the index of the last element in the array. That means you probably initialize it to -1 when the array is empty.

    Furthermore, I think you don't allow duplicates and that each Person will be unique so my solution returns false when you try to insert a duplicate.

    Of course, make sure you resize the array after certain criterium is matched (usually when array is half full).

    public boolean addToArray(T item) {
    
        if (item == null) {
            return false;
        } else if (size == -1) {
            size++;
            sortedArray[size] = item;
            return true;
        } else {
    
            // find the correct insertion point using Binary Search
            int insertionPoint = Arrays
                    .binarySearch(sortedArray, 0, size+1, item);
    
            if (insertionPoint >= 0) {
                // duplicate value
                return false;
            }
    
            // set the insertionPoint to proper value
            insertionPoint = (-(insertionPoint) - 1);
    
            // shift elements to the right of insertionPoint
            for (int i = size + 1; i > insertionPoint; i--) {
                sortedArray[i] = sortedArray[i - 1];
            }
    
            // insert at insertionPoint
            sortedArray[insertionPoint] = item;
    
            // update size
            size++;
    
            return true; //success
        }
    }
    

    Also, you can further simplify your compareTo() method in the Person object.

    public int compareTo(Person p) {
        if(p != null) {
                return p.age - this.age;
        } else throw new NullPointerException();
    }
    

    Right now, sorting is descending. If you want to make it ascending, change:

    return p.age - this.age;
    

    To:

    return this.age - p.age;
    

    Here is a full running example

    Example Output (with ascending sort):

    Person [Country= Uzbekistan, Name:John Doe, Cpr: 200193, age: 21]
    Person [Country= America, Name:Michael Jackson, Cpr: 112345, age: 49]
    Person [Country= Denmark, Name:John, Cpr: 123456, age: 75]
    Person [Country= Germany, Name:Pete, Cpr: 111111, age: 86]