Search code examples
c#linqlambda

changing the sorted column value change the sorting list , while wants to use the ThenByDescending on first ordered list


I have following code, In which there are list of students , and I want to sort the students first by value column which contains decimal values and after that I want to sort the already sorted list with same column but with different values . Just for understanding , I changed values using foreach loop in the below example.

namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Hello World!");

            var students = new List<Student>()
                {
                    new Student() { StudentId=1,Name = "Alice", Appd = 10, Value = 3.5 },
                    new Student() { StudentId=2,Name = "Bob", Appd = 10, Value = 3.7 },
                    new Student() { StudentId=3,Name = "Raul", Appd = 10, Value = 0.1 },
                    new Student() { StudentId=4,Name = "Charlie", Appd = 0, Value = 3.6 },
                    new Student() { StudentId=5,Name = "Dave", Appd = 0, Value = 3.9 },
                    new Student() { StudentId=6,Name = "Emma", Appd = 0, Value = 3.8 }
                };
            var orderedFields = students.OrderByDescending(x => x.Value);//5,6,2,4,1,3
            foreach (  Student s in orderedFields )
            {
                s.Value = 120; 
            }
            orderedFields = orderedFields.ThenByDescending(x => x.Value);
            var newlist1 = orderedFields.Select(X => X.StudentId).ToList(); 
        }
    }

    public class Student
    {
        public int StudentId { get; set; }
        public string Name { get; set; }

        public int Appd { get; set; }

        public double Value { get; set; }
    }
}

but as soon I change the Value column values it start to change the order of items in list , and if I take this in another list then I will be not able to use the ThenByDescending feature results.

This is sample code to simplify the problem , in real example these columns name come from Database and based on those columns I want to sort the list, first by first column and then by another columns mentioned. For example in MySQL it will be something like this order by col1 desc, col2 desc.

As everybody is comments is discussing the clone and then sort again the list . so here is issue with that approach.

#1. First Set sorting values in Value column for each student : Value column first contains for each student either 1 or 0 depending on its enrollment date from the cut off date.

#2 Then on same Value column there is CGPA for each student so student should be sorted based on that.

In short all students who apply before cut off date should appear first and then sort by descending CGPA and then students who apply after cut off date but those also should come in descending order of CGPA.

problem is I have only one column here for values, on which need to be sort.

Second edit :

 if (_trackConfigManager.RankDependentOnFields.Any())
                {
                    infoFields.ForEach(x => x.PropertyToCompare = _trackConfigManager.RankDependentOnFields.FirstOrDefault().FieldId);
    
                    //Order the table withrespect to the firstfield
                    var orderedFields = infoFields.OrderByDescending(x => x.Value);
    
                    //Then skip the first element and order the rest of the fields by descending.
                    foreach (var field in __trackConfigManager.RankDependentOnFields.RemoveFirst())
                    {
                        infoFields.ForEach(x => x.PropertyToCompare = field.FieldId);
                        orderedFields = orderedFields.ThenByDescending(x => x.Value);
                    }
    
                    //Format a studentId, Rank dictionary from the above orderded table
                    int rank = 1 + GetMaxRank(programId, statusId);
    
    }

and RankAggregate class as follow :

public class RankAggregate
    {
        public student_highschool_info HsInfoObj { get; set; }
        public student_interview_info IntInfoObj { get; set; }
        public student StuObj { get; set; }
        private student_program SpObj { get; set; }
        public string PropertyToCompare { get; set; }
        public bool IsDateTimeField { get; set; }
        public long StudentId { get; set; }
        public int Choice { get; set; }

        public double Value
        {
            get
            {
                var tokens = PropertyToCompare.Split(new char[] {':'});
                if (tokens.Count() > 1)
                {
                    PropertyToCompare = (Choice == 1)
                        ? "student_interview_FirstPrgTotalScore"
                        : (Choice == 2) ? "student_interview_SecondPrgTotalScore" : "dummy";
                }
                
                    var fldInfo = ReflectionUtility.GetPublicPropertyName(typeof(student_highschool_info), PropertyToCompare);

                    if (fldInfo != null)
                    {
                        if (HsInfoObj == null)
                            return 0;

                        IsDateTimeField = (fldInfo.PropertyType == typeof(DateTime?));

                        if (IsDateTimeField)
                        {
                            var val1 = ReflectionUtility.GetValueOfPublicProperty(typeof(student_highschool_info),
                                PropertyToCompare, HsInfoObj) ?? 0;

                            var dt = DateTime.Parse(val1.ToString());

                            return -Convert.ToDouble(dt.Ticks);
                        }
                        else
                        {
                            var val1 = ReflectionUtility.GetValueOfPublicProperty(typeof(student_highschool_info),
                                PropertyToCompare, HsInfoObj) ?? 0;

                            return Convert.ToDouble(val1);
                        }


                    }

                    fldInfo = ReflectionUtility.GetPublicPropertyName(typeof(student_interview_info), PropertyToCompare);

                    if (fldInfo != null)
                    {
                        if (IntInfoObj == null)
                            return 0;

                        IsDateTimeField = (fldInfo.PropertyType == typeof(DateTime?));

                        if (IsDateTimeField)
                        {
                            var val1 = ReflectionUtility.GetValueOfPublicProperty(typeof(student_interview_info),
                                PropertyToCompare, IntInfoObj) ?? 0;

                            var dt = DateTime.Parse(val1.ToString());

                            return -Convert.ToDouble(dt.Ticks);
                        }
                        else
                        {
                            var val1 = ReflectionUtility.GetValueOfPublicProperty(typeof(student_interview_info),
                                PropertyToCompare, this.IntInfoObj) ?? 0;

                            return Convert.ToDouble(val1);
                        }

                    }

                    fldInfo = ReflectionUtility.GetPublicPropertyName(typeof(student), PropertyToCompare);

                    if (fldInfo != null)
                    {
                        if (StuObj == null)
                            return 0;

                        IsDateTimeField = (fldInfo.PropertyType == typeof(DateTime?));

                        if (IsDateTimeField)
                        {
                            var val1 = ReflectionUtility.GetValueOfPublicProperty(typeof(student),
                                PropertyToCompare, StuObj) ?? 0;

                            var dt = DateTime.Parse(val1.ToString());

                            return -Convert.ToDouble(dt.Ticks);
                        }
                        else
                        {
                            var val1 = ReflectionUtility.GetValueOfPublicProperty(typeof(student),
                                PropertyToCompare, this.StuObj) ?? 0;

                            return Convert.ToDouble(val1);
                        }
                    }

                    return 0.0;
            }    
        }

        public RankAggregate(long studentId, student_highschool_info _hsInfo, student_interview_info _intInfo, student _profileInfo, student_program _spInfo)
        {
            StudentId = studentId;
            HsInfoObj = _hsInfo;
            IntInfoObj = _intInfo;
            StuObj = _profileInfo;
            SpObj = _spInfo;

            if (SpObj != null)
            {
                Choice = SpObj.choice;
            }
        }

       
    }

Solution

  • Don't know why can't you add another field to the Student class, anyway since you can't do that, you have to fix these values in some places, for example using a tuple:

    var studentsWithValues = students.Select(s => (s, s.Value))
                                     .ToList();
    

    Then after changing the values, you can sort the above array:

    var orderedFields = studentsWithValues.OrderByDescending(t => t.Value)
                                          .ThenByDescending(t => t.s.Value)
                                          .Select(t => t.s)
    

    Update for uncertain columns

    Bind each student object with a list of values:

    var studentsWithValues = students.Select(s => new
    {
        Student = s,
        Values = new List<double> { s.Value }
    })
    .ToList();
    

    After the values are updated, append each value to the binded list:

    UpdateValues();
    studentsWithValues.ForEach(t => t.Values.Add(t.Student.Value));
    

    Then you can sort these values:

    var e = studentsWithValues.OrderByDescending(t => t.Values[0]);
    var valueCount = studentsWithValues.First().Values.Count;
    for (int i = 1; i < valueCount; i++)
    {
        int j = i;
        e = e.ThenByDescending(t => t.Values[j]);
    }
    var orderedFields = e.Select(t => t.Student);