fkr
fkr

Reputation: 155

Sorting by last name and first name c#

This is another homework here. I need to sort students by it's last name and first name (firstly last name and secondly first name). The full list of students must be edited alphabetical.

What works so far:

If i type in 3 students with same Last name, it sorts correctly.

Lets say:

Richardson Mark Richardson Mike Richardson Matt

The correct sorting order is:

Richardson Mark Richardson Matt Richardson Mike

It also work when last name's start with same letter and are look alike

Lets say:

Richardson Mark Richmond Luke Rikkard Matt

Sorts as:

Richardson Mark Richmond Luke Rikkard Matt

My problem

The code doesn't sort 3 entirely different last name's (etc, Richardson, Markson, Bekhs)...

Please notice that only basic functions are allowed and must be programmed like bellow!

private static void sortAlpphabetical(Student[] studentList)
{
    for (int i = 1; i < studentList.Length; i++)
    {
        for (int j = 0; j < studentList.Length - 1; j++)
        {
            string lastName1 = studentList[j].lastName.ToLower() + studentList[j].name.ToLower();
            string lastName2 = studentList[j + 1].lastName.ToLower() + studentList[j + 1].name.ToLower();
            for (int k = 0; k < lastName1.Length; k++)
            {
                if (returnIndex(lastName2[k]) > returnIndex(lastName1[k]))
                {
                    Student currentStudent = studentList[j];
                    studentList[j] = studentList[j + 1];
                    studentList[j + 1] = currentStudent;
                }
            }
        }
    }
    Console.WriteLine("List of students:\n");
    for (int i = 0; i < studentList.Length; i++)
    {
        Console.WriteLine("//code");
    }
}

When i try to sort 3 different last names, it gives me Index was outside the bounds of the array. Error

An unhandled exception of type 'System.IndexOutOfRangeException' occurred in work.exe

Additional information: Index was outside the bounds of the array.

Upvotes: 1

Views: 7469

Answers (5)

wladyslaw.czyzewski
wladyslaw.czyzewski

Reputation: 770

using System.Linq;

Student[] sorted = studentList.OrderBy(x=>x.lastName).ThenBy(x=>x.name).ToArray();

Upvotes: 0

James
James

Reputation: 9985

k here makes the assumption that lastName1 is longer than lastName2

for (int k = 0; k < lastName1.Length; k++)
{
    if (returnIndex(lastName2[k]) > returnIndex(lastName1[k]))
    {
        Student currentStudent = studentList[j];
        studentList[j] = studentList[j + 1];
        studentList[j + 1] = currentStudent;
    }
}

This should prevent that by preventing the loop checking beyond the length of which ever is shorter

int shortestNameLength = Math.Min(lastName1.Length, lastName2.Length);
for (int k = 0; k < shortestNameLength ; k++)

After some testing your algorithm has another problem. It will continue comparing to the last character in the name. It needs to stop once it has determined the order

Compare a character

  • If the same, check next character
  • If greater, swap, were done here.
  • If less, do nothing, were done here.

To summarise, replace

for (int k = 0; k < lastName1.Length; k++)
{
    if (returnIndex(lastName2[k]) > returnIndex(lastName1[k]))
    {
        Student currentStudent = studentList[j];
        studentList[j] = studentList[j + 1];
        studentList[j + 1] = currentStudent;
    }
}

with

int shortestNameLength = Math.Min(lastName1.Length, lastName2.Length);
for (int k = 0; k < shortestNameLength ; k++)
{
    int c1 = returnIndex(lastName1[k]);
    int c2 = returnIndex(lastName2[k]);
    if (c1 == c2)
    {
        continue;
    }
    if (c1 > c2)
    {
        Student currentStudent = studentList[j];
        studentList[j] = studentList[j + 1];
        studentList[j + 1] = currentStudent;
    }
    break;
}

The complete method now looks something like this...

    private static void sortAlpphabetical(Student[] studentList)
    {
        for (int i = 1; i < studentList.Length; i++)
        {
            for (int j = 0; j < studentList.Length - 1; j++)
            {
                string lastName1 = studentList[j].lastName.ToLower() + studentList[j].name.ToLower();
                string lastName2 = studentList[j + 1].lastName.ToLower() + studentList[j + 1].name.ToLower();
                int shortestNameLength = Math.Min(lastName1.Length, lastName2.Length);
                for (int k = 0; k < shortestNameLength; k++)
                {
                    int c1 = returnIndex(lastName1[k]);
                    int c2 = returnIndex(lastName2[k]);
                    if (c1 == c2)
                    {
                        continue;
                    }
                    if (c1 > c2)
                    {
                        Student currentStudent = studentList[j];
                        studentList[j] = studentList[j + 1];
                        studentList[j + 1] = currentStudent;
                    }
                    break;
                }
            }
        }
        Console.WriteLine("List of students:\n");
        for (int i = 0; i < studentList.Length; i++)
        {
            Console.WriteLine(string.Format("{0} {1}", studentList[i].name, studentList[i].lastName));
        }
    }

Upvotes: 1

RePierre
RePierre

Reputation: 9566

You can use IComparer interface to specify the order of your objects.

This is the code I scrapped in LinqPad (using the names provided by @Serv - yeah I am that lazy...)

void Main()
{
    var students = new List<Student>()
    {
        new Student("Alphonso", "Zander"),
        new Student("Berta", "Zander"),
        new Student("Giacomo", "Zander"),
        new Student("Marc", "Lastly"),
        new Student("God", "Allmighty")
    };
    students.Sort(new StudentComparer());
    students.Dump();
}

class Student
{
    public Student(string firstName, string lastName)
    {
        FirstName = firstName;
        LastName = lastName;
    }
    public string FirstName{get;set;}
    public string LastName{get;set;}
}

class StudentComparer:IComparer<Student>
{
    public int Compare(Student a, Student b)
    {
        var lastName = a.LastName.CompareTo(b.LastName);
        if(lastName == 0)
            return a.FirstName.CompareTo(b.FirstName);
        return lastName;
    }   
}

Unless you want to rewrite the sorting algorithm used by Sort method the code above should suffice for you.

And here are the results:

Results.

Upvotes: 0

Moho
Moho

Reputation: 16498

You need to check the length of the arrays you're accessing. If lastName1 doesn't have a character at offset k (i.e. lastName1.length == k), we know lastName2 is greater than lastName1. If lastName2 does not have a character at offset k (i.e. lastName2.length <= k), it can't be greater than lastName1.

Change

if (returnIndex(lastName2[k]) > returnIndex(lastName1[k]))

to

if( lastName1.length == k ||
    ( lastName2.length > k &&
      returnIndex(lastName2[k]) > returnIndex(lastName1[k]) ) )

Upvotes: 1

Marco
Marco

Reputation: 23937

Just scratched this up in LinqPad, which should give you the desired output, unless you are supposed to use for-loops and classic arrays.

void Main()
{
    var students = new List<student>() 
    {
      new student("Alphonso", "Zander"),
      new student("Berta", "Zander"),
      new student("Giacomo", "Zander"),
      new student("Marc", "Lastly"),
      new student("God", "Allmighty")
    };

    var sortedStudents = students.OrderBy(s => s.lastName).ThenBy(s => s.firstName).Dump();
}

// Define other methods and classes here
class student
{
    public student(string fname, string lname)
    {
     this.firstName = fname; this.lastName = lname;
    }
  public string firstName { get; set; }
  public string lastName { get; set; }
}

Output:

firstName lastName 
God       Allmighty 
Marc      Lastly 
Alphonso  Zander 
Berta     Zander 
Giacomo   Zander 

Upvotes: 0

Related Questions