operamaxi
operamaxi

Reputation: 79

Sorting one array from another's one date

I have Visual Studio 2019. The project is a .Net Windows Form on C# on .Net Framework 4.8.

I have got two arrays.

The first one contains a random number of string values (since they come on a string[]), for example:

AB5XHBC1
NMAK72B8
WB5XHBC1
KCZUH528
NZ9YHF3D
PFKR6WNA

The second one will always have the same length of the first one, but their values are date-strings, and it could be some string.empty or repeated values in some cases:

06/10/2020
08/05/2018

01/12/2020
01/01/2009
01/12/2020

What I need to do is sort the first array based on the second one dates. I tried the Array.Sort method but it does not give me the expected result. I'm not really sure if I have used it wrong.

The "null" values must be the firsts, then the newer date (on the top) to the older date (on the bottom), so the resulting array of this example would have to be sort like this (from 0 to 5 position):

WB5XHBC1
KCZUH528
PFKR6WNA
NMAK72B8
AB5XHBC1
NZ9YHF3D

Thanks in advance.

Upvotes: 0

Views: 100

Answers (2)

Matthew Watson
Matthew Watson

Reputation: 109732

You could implement a comparer for your dates (which should implement IComparer<string>) and then use Array.Sort(keys, values, comparer) like so:

using System;
using System.Collections.Generic;

namespace Demo
{
    static class Program
    {
        public static void Main()
        {
            string[] data = 
            {
                "AB5XHBC1",
                "NMAK72B8",
                "WB5XHBC1",
                "KCZUH528",
                "NZ9YHF3D",
                "PFKR6WNA"
            };

            string[] dates =
            {
                "06/10/2020",
                "08/05/2018",
                "",
                "01/12/2020",
                "01/01/2009",
                "01/12/2020"
            };

            Array.Sort(dates, data, new CompareDates());

            Console.WriteLine(string.Join("\n", data));
        }
    }

    public sealed class CompareDates: IComparer<string>
    {
        public int Compare(string x, string y)
        {
            var xd = DateTime.TryParse(x, out DateTime d1) ? d1 : DateTime.MaxValue;
            var yd = DateTime.TryParse(y, out DateTime d2) ? d2 : DateTime.MaxValue;

            return yd.CompareTo(xd);
        }
    }
}           

However, this gives the output as:

WB5XHBC1
KCZUH528
PFKR6WNA
AB5XHBC1
NMAK72B8
NZ9YHF3D

I believe this is because your expected results have an error. The second-oldest date is "08/05/2018", which corresponds to the string "NMAK72B8". Therefore, according to your specification, "NMAK72B8" should be second from the end - but in your expected results, "AB5XHBC1" is second from the end.

Try it online (.Net Fiddle).

One thing to watch out for is the date parsing. The code above parses the dates in the current locale, which is assumed to be UK (for the dd/mm/yyyy date format). If you want to parse other date formats, you'll have to change the code accordingly.

Upvotes: 4

trashr0x
trashr0x

Reputation: 6565

You can store these in a List of Tuple<string, DateTime>. I've hardcoded the values in the example below - as other commenters have said, you need to properly parse the date strings into proper DateTime objects, etc. I leave that exercise to you.

var list = new List<(string RandomString, DateTime Date)>
{
    ("AB5XHBC1", DateTime.Parse("06/10/2020")),
    ("NMAK72B8", DateTime.Parse("08/05/2018")),
    ("WB5XHBC1", DateTime.MaxValue), // simulating null, see below
    ("KCZUH528", DateTime.Parse("01/12/2020")),
    ("NZ9YHF3D", DateTime.Parse("01/01/2009")),
    ("PFKR6WNA", DateTime.Parse("01/12/2020")),
};

var sorted = list.OrderByDescending(x => x.Date);

For the case of the null dates appearing first, you can check if the particular date string is null. If it is, assign DateTime.MaxValue as a value, otherwise parse it and use the actual value. The logic of this check could resemble the one below:

string.IsNullOrEmpty(whateverStringDate) ? DateTime.MaxValue : DateTime.Parse(whateverStringDate);

This should point you in the right direction, @Matthew Watson's answer would be a much more elegant and complete solution.

Upvotes: 3

Related Questions