Collection sorting in .Net can also be played like this

background:

public class StockQuantity
    {
        public StockQuantity(string status, DateTime dateTime, int quantity)
        {
            Status = status;
            DateTime = dateTime;
            Quantity = quantity;
        }

        public string Status { get; set; }
        public DateTime DateTime { get; set; }
        public int Quantity { get; set; }

}


This object mainly has three fields. The current business requirement is to obtain a collection of StockQuantities whose type is List<StockQuantity>. The collection needs to be sorted three times. The sorting rules and priorities are as follows:
1. The ones whose Status is empty are listed at the back. , the ones that are not empty are listed in the front, do not care about the content of Status, only care about whether Status is empty.
2. Sort DateTime in ascending order.
3. Quantity sort in ascending order.

Xiaobai, my approach:


I only know that the collection can be sorted by OderBy, and the above three rules are used, so the design idea is as follows.

1. StockQuantities.OrderBy(u=>u.Status)
error,
the sorting rule will not only consider whether the Status is empty, but also consider the content of the Status.
If Status is ["b","c",null,"d"], then the sort result is [null,"b","c","d"].
And the result we want is ["b","c","d",null] (put the null to the end directly, and nothing else)
what to do?

Don't know for now, don't care

2. Sort DateTime in ascending order, which is a simple
StockQuantities.OrderBy(u=>u.DateTime)
half pair!
Why half right, see below

3. Under the premise of sorting 2, using OrderBy, that is, StockQuantities.OrderBy(u=>u.DateTime).OrderBy(u=>u.Quantity) is
wrong!
The above expression is equivalent to the following two expressions:

StockQuantities = StockQuantities.OrderBy(u=>u.DateTime)
StockQuantities = StockQuantities.OrderBy(u=>u.Quantity)

So the first code is waste code, and the final sorting is still sorted by Quantity.
Although I am a novice, I still understand that this is wrong, so my approach is

stockQuantities = stockQuantities.OrderBy(u => u.DateTime).ToList();

            foreach (var dateOrder in stockQuantities)
            {
                var datetimeOrderBy = stockQuantities.Where(u => u.DateTime.Date == dateOrder.DateTime.Date) .OrderBy(u => u.Count);

                foreach (var countOrder in datetimeOrderBy)
                {
                    if (countOrder.OutPut == false)
                    {
                        Console.WriteLine($"{countOrder.Status}-{countOrder.DateTime}-{countOrder.Count}");
                        countOrder.OutPut = true;
                    }
                    
                }
            }
            Console.ReadKey();


Using a double-layer loop, first get the data dateOrder sorted by time, then go to all the data on the same day as the data and sort the Quantity. In order to prevent repeated output, I also added the Output property to the StockQuantity object. When If the property is false, the content of the object is output, and the Output property is set to true, so that the output will not be repeated, and the DateTime is sorted first, and then the Quantity is sorted.
So easy! !
However, when he happily submitted such code, he was severely despised by his colleagues and said, "What rotten code!" But is there any better code than this?

Poured a cup of tea for my colleague, lit a cigarette, and asked for advice humbly.

Big guy's way:


My colleague told me two tricks, namely conditional sorting and multi-level sorting.

What is conditional sorting and how to use it?

1. StockQuantities.OrderBy(u=>u.Status==null)
This is the conditional sorting, but at first glance, it gives the illusion that the status is empty in front of the row, and the row is not empty.
In fact, it is not. We see an expression in OrderBy with a return value of type bool. The ordering first sorts the result with a result of 0 (false), and then sorts the result with a result of 1 (true) . This sort only considers the returned bool value and does not consider the specific value of the parameter, so let's call it conditional sorting.
Fully complies with the requirements of collation 1.

What is multi-level sorting and how to use it?


2. Although the sorting of my code above can be used to sort DateTime first and then Quantity, but the time complexity of the algorithm is n*n, and the output field is added to StockQuantity, which is obviously unscientific.
However, using multiple OrderBy consecutively will only take effect for the last OrderBy, so there is no way to do it, so you should use ThenBy at this time ! !
Using ThenBy, the above three sorting rules can be simplified as follows:
stockQuantities = stockQuantities.OrderBy(u => u.Status==null).ThenBy(u => u.DateTime).ThenBy(u => u.Quantity).ToList ();
can perfectly realize the secondary sorting under the premise of the previous sorting.

The complete code after optimization is as follows:

using System;
using System.Collections.Generic;
using System.Linq;

namespace OrderBy
{
    class Program
    {
        static void Main(string[] args)
        {
            var stockQuantities = new List<StockQuantity>()
            {
                new StockQuantity( " Normal " , new DateTime( 2017 , 4 , 16 ), 12 ),
                 new StockQuantity( " Normal " , new DateTime( 2017 , 4 , 17 ), 15 ),
                 new StockQuantity( " Defective " , new DateTime( 2017 , 4 , 16 ), 10 ),
                 new StockQuantity("残次品",new DateTime(2017,4,17),8 ),
                new StockQuantity(null,new DateTime(2017,4,18),8 ),
            };

            stockQuantities = stockQuantities.OrderBy(u => u.Status==null).ThenBy(u => u.DateTime).ThenBy(u => u.Quantity).ToList();

            foreach (var stockQuantity in stockQuantities)
            {
                Console.WriteLine($"{stockQuantity.Status}-{stockQuantity.DateTime}-{stockQuantity.Quantity}");
            }

            Console.ReadKey();
        }
    }

    public class StockQuantity
    {
        public StockQuantity(string status, DateTime dateTime, int quantity)
        {
            Status = status;
            DateTime = dateTime;
            Quantity = quantity;
        }

        public string Status { get; set; }
        public DateTime DateTime { get; set; }
        public int Quantity { get; set; }

    }
}

A simple sorting optimization reduces the time complexity of the program from N*N to N, so I share these two sorting techniques here, hoping to help those who don't know.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325309936&siteId=291194637