14 Replies - 613 Views - Last Post: 11 July 2020 - 04:32 AM Rate Topic: -----

#1 capsyl   User is offline

  • New D.I.C Head

Reputation: 1
  • View blog
  • Posts: 49
  • Joined: 17-June 20

Sort array so null elements comes last?

Posted 07 July 2020 - 09:46 AM

Say I have the following code. How can I sort this so all null elements comes last? So [2] takes slot [1] for instance?

            students = new Student[4];

            students[0] = new Student("Jonny Rickson", 20, "Man", false, new char[] { 'c', 'd' });
            //students[1] = new Student("Anna Montana", 30, "Woman", false, new char[] { 'a', 'b' });
            students[2] = new Student("Eric Johnson", 20, "Man", false, new char[] { 'a', 'b' });
            //students[3] = new Student("Steven Anderson", 20, "Man", false, new char[] { 'a', 'b' });



Is This A Good Question/Topic? 0
  • +

Replies To: Sort array so null elements comes last?

#2 modi123_1   User is online

  • Suitor #2
  • member icon



Reputation: 15804
  • View blog
  • Posts: 63,308
  • Joined: 12-June 08

Re: Sort array so null elements comes last?

Posted 07 July 2020 - 09:49 AM

The implementation of a 'bubble sort' would do it.

Use a for loop, start at 0, compare with start+1.
If start is null then swap with start+1.
Repeat.
Was This Post Helpful? 0
  • +
  • -

#3 capsyl   User is offline

  • New D.I.C Head

Reputation: 1
  • View blog
  • Posts: 49
  • Joined: 17-June 20

Re: Sort array so null elements comes last?

Posted 08 July 2020 - 08:45 AM

Hmm not following with the compare part besides of being null.
But this is what I've put together so far where I'm stuck:

            for (int outerLoop = 0; outerLoop < students.Length; outerLoop++)
            {
                for (int innerLoop = 0; innerLoop < students.Length; innerLoop++)
                {
                    if (students[outerLoop] == null)
                    {
                        var tempObject = students[outerLoop]; 
                        students[outerLoop] = students[innerLoop+1]; 
                        students[innerLoop+1] = tempObject;
                    }
                }
            }

Was This Post Helpful? 0
  • +
  • -

#4 modi123_1   User is online

  • Suitor #2
  • member icon



Reputation: 15804
  • View blog
  • Posts: 63,308
  • Joined: 12-June 08

Re: Sort array so null elements comes last?

Posted 08 July 2020 - 08:52 AM

In what way are you stuck?
Was This Post Helpful? 0
  • +
  • -

#5 capsyl   User is offline

  • New D.I.C Head

Reputation: 1
  • View blog
  • Posts: 49
  • Joined: 17-June 20

Re: Sort array so null elements comes last?

Posted 08 July 2020 - 09:00 AM

It didn't sort the null values correctly. Fixed it a bit, although it put all null values to the beginning. Would like it to be reversed. Feels like I'm guessing to be honest without really know what I'm doing which feels frustrating.

But the code which I would like to sort in reverse instead:
            for (int outerLoop = 0; outerLoop < students.Length-1; outerLoop++)
            {
                for (int innerLoop = 0; innerLoop < students.Length-1; innerLoop++)
                {
                    if (students[outerLoop+1] == null)
                    {
                        var tempObject = students[outerLoop+1]; 
                        students[outerLoop+1] = students[innerLoop]; 
                        students[innerLoop] = tempObject;
                    }
                }
            }

Was This Post Helpful? 0
  • +
  • -

#6 modi123_1   User is online

  • Suitor #2
  • member icon



Reputation: 15804
  • View blog
  • Posts: 63,308
  • Joined: 12-June 08

Re: Sort array so null elements comes last?

Posted 08 July 2020 - 09:10 AM

Quote

Feels like I'm guessing to be honest without really know what I'm doing which feels frustrating.

Then stop, take a breath, and put a breakpoint on the function. Step through it and see (you can mouse over, or drag a variable into the 'Watch' window) what is happening.

Ex: Debugging tutorial: https://www.dreaminc...ugging-express/
Was This Post Helpful? 0
  • +
  • -

#7 capsyl   User is offline

  • New D.I.C Head

Reputation: 1
  • View blog
  • Posts: 49
  • Joined: 17-June 20

Re: Sort array so null elements comes last?

Posted 08 July 2020 - 09:42 AM

Thanks I'm using the debugger frequently though with breakpoints to see how the code is running. So overall I understand.

It's just this sorting thing when multiple things're are dependent on each other, like multiple loops which makes me lose context.
Was This Post Helpful? 0
  • +
  • -

#8 modi123_1   User is online

  • Suitor #2
  • member icon



Reputation: 15804
  • View blog
  • Posts: 63,308
  • Joined: 12-June 08

Re: Sort array so null elements comes last?

Posted 08 July 2020 - 09:58 AM

I would suggest starting smaller than. Remove the complexity. Try with one loop.
Was This Post Helpful? 0
  • +
  • -

#9 capsyl   User is offline

  • New D.I.C Head

Reputation: 1
  • View blog
  • Posts: 49
  • Joined: 17-June 20

Re: Sort array so null elements comes last?

Posted 08 July 2020 - 11:02 AM

I hear what you say and indeed. I feel pretty confident with the iteration of one loop. But when they're combined it gets more complex. Any suggestions where to read more about this? Is it called nested loops?
Was This Post Helpful? 0
  • +
  • -

#10 modi123_1   User is online

  • Suitor #2
  • member icon



Reputation: 15804
  • View blog
  • Posts: 63,308
  • Joined: 12-June 08

Re: Sort array so null elements comes last?

Posted 08 July 2020 - 11:15 AM

Yes it is called nested loops.

You need to keep an eye on which loop control variable is being used and where.
Was This Post Helpful? 0
  • +
  • -

#11 Skydiver   User is online

  • Code herder
  • member icon

Reputation: 7462
  • View blog
  • Posts: 25,113
  • Joined: 05-May 12

Re: Sort array so null elements comes last?

Posted 08 July 2020 - 05:32 PM

Out of curiosity, how did students[1] and students[3] become null? Perhaps instead of setting those entries to null and then later trying to compact the array, you could shift things down at the time you were going to set them to null. In other words, instead of:
void RemoveStudent(int index)
{
    students[index] = null;
}


you would have code that looks like:
void RemoveStudent(int index)
{
    for(int i = index; i < students.Length - 1; i++)
    {
        students[i] = students[i + 1];
    }

    if (students.Length >= 1)
        students[students.Length - 1] = null;
}



Alternatively, instead of "sorting" the array, you could simply "compact" the array. Here's pseudo-code:
let dst = 0
let src = 0
for src = 0..array.Length-1 do
    if array[src] is not null
        array[dst] = array[src]
        dst = dst + 1


Was This Post Helpful? 0
  • +
  • -

#12 Sheepings   User is offline

  • D.I.C Lover
  • member icon

Reputation: 241
  • View blog
  • Posts: 1,303
  • Joined: 05-December 13

Re: Sort array so null elements comes last?

Posted 09 July 2020 - 04:22 PM

You seem to be going down a rabbit hole. Why would you keep null items in the array? Anyway, here is something I flung together which might give you a starting point.

Assume you have a class of student :
        public class Student
        {
            private string Name;
            private int Age;
            private string Sex;
            private bool e_bool;
            private char[] Grade = { 'a', 'b', 'c', 'd' };

            public Student(string student_Name, int student_Age, string student_Sex, bool student_Bool, char[] student_Grade)
            {
                Student_Name = student_Name;
                Student_Age = student_Age;
                Student_Sex = student_Sex;
                Student_Bool = student_Bool;
                Student_Grade = student_Grade;
            }

            public string Student_Name
            {
                get { return Name; }
                set { Name = value; }
            }
            public int Student_Age
            {
                get { return Age; }
                set { Age = value; }
            }
            public string Student_Sex
            {
                get { return Sex; }
                set { Sex = value; }
            }
            public bool Student_Bool
            {
                get { return e_bool; }
                set { e_bool = value; }
            }
            public char[] Student_Grade
            {
                get { return Grade; }
                set { Grade = value; }
            }
        }

Remembers, I'd be in favour of removing your nulls first, and you would also find this easier to work with if you were using a List<T> where T would be Student. Ie List<Student> but since that's not what you are doing, I will show you how to sort.

You already have your array of student :
            students[0] = new Student("Jonny Rickson", 20, "Man", false, new char[] { 'c', 'd' });
            //students[1] = new Student("Anna Montana", 30, "Woman", false, new char[] { 'a', 'b' });
            students[2] = new Student("Eric Johnson", 20, "Man", false, new char[] { 'a', 'b' });
            //students[3] = new Student("Steven Anderson", 20, "Man", false, new char[] { 'a', 'b' });

To sort that, you would use an IOrderedEnumerable<T> with a little Linq like the following :
IOrderedEnumerable<Student> Sorted_Array_Result = students.OrderBy(x => x == null).ThenBy(x => x != null);

Where the sorted array result equals the students array, which is OrderedBy Linq and then by the polar opposite of what we ordered it by. This puts the null objects in your array at the end of your sorted array result.

Now to the part that doesn't make sense... If you want to execute these students results or something to that effect, you need to filter the nulls at the end of the array or you will be met generously with a null reference exception unless we filter the loop :

            foreach (Student student in Sorted_Array_Result.TakeWhile(x => x != null))
            {
                Debug.WriteLine($"Student : {student.Student_Name}, aged {student.Student_Age}, of origin {student.Student_Sex}, graded : {student.Student_Grade[0]} & {student.Student_Grade[1]}");
            }

In this example, its the .TakeWhile(x => x != null) which prevents the nulls from being iterated. That's because we are telling the loop to iterate over the Sorted_Array_Result by means of taking only the students whom are not null. This is done with : .TakeWhile(x => x != null) - If you'd prefer to handle the null reference exception yourself and include nulls in your foreach loop, then remove take while.

Output:
Student : Jonny Rickson, aged 20, of origin Man, graded : c & d
Student : Eric Johnson, aged 20, of origin Man, graded : a & b

Spoiler

This post has been edited by Sheepings: 09 July 2020 - 04:27 PM

Was This Post Helpful? 1
  • +
  • -

#13 Skydiver   User is online

  • Code herder
  • member icon

Reputation: 7462
  • View blog
  • Posts: 25,113
  • Joined: 05-May 12

Re: Sort array so null elements comes last?

Posted 09 July 2020 - 08:38 PM

Traditionally, when CS students are taught sorting, they are taught how to sort in place. What is happening above with the use of OrderBy() is that a new collection is generated.

Anyway the key to Sheepings' sorting above is this little nugget: x == null. All that is need is the following:
students = students.OrderBy(x => x == null).ToArray();


There's no need for the ThenBy(). The ToArray() just builds a new array from the sorted collection.

The lambda passed to OrderBy() is supposed to return a key value for each of the items within the collection on which OrderBy() is working on. So in this case, when the entry in the student array is null, the key value of true is returned, and conversely when the entry is not null, key value of false is returned. The C# default comparison sorts false as coming before true. Et viola. The reason why this sorting works like compaction is that the LINQ OrderBy() does a stable sort. If it didn't do a stable sort, there there is a possibility that the non-null items would get re-arranged.

Here's another version that sorts in place:
using System;
using System.Collections.Generic;
using System.Linq;

namespace ConsoleTest
{
    class Program
    {
        static void Main()
        {
            var students = new Student[4];

            students[0] = new Student("Jonny Rickson", 20, "Man", false, new char[] { 'c', 'd' });
            //students[1] = new Student("Anna Montana", 30, "Woman", false, new char[] { 'a', 'b' });
            students[2] = new Student("Eric Johnson", 20, "Man", false, new char[] { 'a', 'b' });
            //students[3] = new Student("Steven Anderson", 20, "Man", false, new char[] { 'a', 'b' });

            ShowStudentsArray("Before sort");
            Array.Sort(students, Comparer<Student>.Create(Compare));
            ShowStudentsArray("After sort");

            int Compare(Student left, Student right)
            {
                int a = left == null ? 1 : 0;
                int b = right == null ? 1 : 0;
                return a - b;
            }

            void ShowStudentsArray(string title)
            {
                Console.WriteLine(title);
                for (int i = 0; i < students.Length; i++)
                    Console.WriteLine($"students[{i}] = {students[i]}");
            }
        }
    }

    class Student
    {
        public string Name { get; }
        public int Age { get; }
        public string Gender { get; }
        public bool GradeAtRisk { get; }
        public IEnumerable<char> Grades { get; }

        public Student(string name, int age, string gender, bool gradeAtRisk, IEnumerable<char> grades)
        {
            Name = name;
            Age = age;
            Gender = gender;
            GradeAtRisk = gradeAtRisk;
            Grades = grades.ToList();
        }

        public override string ToString()
        {
            var grades = string.Join(", ", Grades);
            return $"{Name}, {Age}, {Gender}, Grade at Risk: {GradeAtRisk}, Grades: {grades}";
        }
    }
}


In the code above a similar trick is played:
int a = left == null ? 1 : 0;
int b = right == null ? 1 : 0;


If the left (or right) student is null, then give it a key value of 1 otherwise a key value of 0.

Compare() is supposed to return:
-1 if left < right
0 if left == right
1 if left > right

So to effect the comparison, a - b is returned.

(Unless you naturally think algebraically, it takes a little while to be convinced that:
if x < y, then x - y < 0;
if x > y, then x - y > 0; and
if x == y, then x - y == 0. I know that I struggled with it in high school.)
Was This Post Helpful? 1
  • +
  • -

#14 Sheepings   User is offline

  • D.I.C Lover
  • member icon

Reputation: 241
  • View blog
  • Posts: 1,303
  • Joined: 05-December 13

Re: Sort array so null elements comes last?

Posted 10 July 2020 - 06:01 AM

For clarity, I added ThenBy so they; the OP new that there was an additional way to sort by alternate conditions.

But your example is more pure Skydiver. I also prefer the use of the override which is something I didn't add.
Was This Post Helpful? 0
  • +
  • -

#15 capsyl   User is offline

  • New D.I.C Head

Reputation: 1
  • View blog
  • Posts: 49
  • Joined: 17-June 20

Re: Sort array so null elements comes last?

Posted 11 July 2020 - 04:32 AM

Thanks! I'll look into it further :)
Was This Post Helpful? 0
  • +
  • -

Page 1 of 1