C
C#11mo ago
KingHarem16

✅ Specific Sorting Algorithm

Hey i have been breaking my head about this problem and i have no clue how to solve this. Im a trainee Developer in Germany and i have been assigned to develop a WebApi and a Website with a Table that needs to show Shipments which are about to be due. I have a DataModel with different fields like Desired Shipment Date (Type: DateTime), Last Possible Shipment Date, Punctual (Type: Boolean) and various other field but these dont matter for this problem. So now i have got a unsorted List of these models, which i have to sort after certain criterias: So they have to be sorted first after their last possible Shipment Date in ascending Order, if that date is already due then the records have to be sorted after the punctual flag with the Shipment Date. I really dont know how to implement this and looking at least for a lead in the right direction.
48 Replies
Pobiega
Pobiega11mo ago
You mention a table, is this in a SQL database of sorts? If so, are you using something like EF Core or Dapper to access that database?
KingHarem16
KingHarem1611mo ago
its just data from our erp system that i have to put in a table in the web-gui its just about sorting a List of models after these criterias
Pobiega
Pobiega11mo ago
Okay, but what datatype is that table? C# is a strictly typed system
KingHarem16
KingHarem1611mo ago
its a List of a custom class containing the attributes Desired Shipment Date (DateTime) and Punctual (Flag). Its just about sorting the elements of the list in place on the mentioned criterias.
Pobiega
Pobiega11mo ago
ok so a List<T>
KingHarem16
KingHarem1611mo ago
yep
Pobiega
Pobiega11mo ago
alright so first it sorts by desired shipment date, but if that date has already passed, then what? and do those items go at the front or back of the list?
KingHarem16
KingHarem1611mo ago
to the front of list
Pobiega
Pobiega11mo ago
mhm. and how does punctual and last possible shipment date come into it?
KingHarem16
KingHarem1611mo ago
oh sry mb the last possible is irrelevant. So if the shipment date is already due then all records where the punctual flag is true need to come first then records which are due but have no true punctual flag
Pobiega
Pobiega11mo ago
ok. easy. you just need to use OrderBy and ThenBy
KingHarem16
KingHarem1611mo ago
so it would be ListToSort.OrderBy(x => x.DesiredShipmentDate).ThenBy(x => x.Punctual)
Pobiega
Pobiega11mo ago
might need a little more then that, but give it a try
KingHarem16
KingHarem1611mo ago
ok
Pobiega
Pobiega11mo ago
Shipment { DesiredShipmentDate = 2023-08-22 12:46:56, Punctual = True, IsDue = True }
Shipment { DesiredShipmentDate = 2023-08-30 12:46:56, Punctual = True, IsDue = True }
Shipment { DesiredShipmentDate = 2023-08-26 12:46:56, Punctual = False, IsDue = True }
Shipment { DesiredShipmentDate = 2023-09-02 12:46:56, Punctual = True, IsDue = False }
Shipment { DesiredShipmentDate = 2023-09-02 12:46:56, Punctual = False, IsDue = False }
Shipment { DesiredShipmentDate = 2023-09-03 12:46:56, Punctual = False, IsDue = False }
Shipment { DesiredShipmentDate = 2023-09-06 12:46:56, Punctual = False, IsDue = False }
Shipment { DesiredShipmentDate = 2023-08-22 12:46:56, Punctual = True, IsDue = True }
Shipment { DesiredShipmentDate = 2023-08-30 12:46:56, Punctual = True, IsDue = True }
Shipment { DesiredShipmentDate = 2023-08-26 12:46:56, Punctual = False, IsDue = True }
Shipment { DesiredShipmentDate = 2023-09-02 12:46:56, Punctual = True, IsDue = False }
Shipment { DesiredShipmentDate = 2023-09-02 12:46:56, Punctual = False, IsDue = False }
Shipment { DesiredShipmentDate = 2023-09-03 12:46:56, Punctual = False, IsDue = False }
Shipment { DesiredShipmentDate = 2023-09-06 12:46:56, Punctual = False, IsDue = False }
this looks sorted according to your rules, right?
KingHarem16
KingHarem1611mo ago
sadly no all the records if they are due and have the punctual as true need to come first then the ones which have punctual as false and are due sry for the misunderstanding
Pobiega
Pobiega11mo ago
but thats what it does due and punctual > due and not punctual > not due thats the order they are in
KingHarem16
KingHarem1611mo ago
oh im dumb nvm but how i tried it like this
Pobiega
Pobiega11mo ago
so, what is the most important ordering? ie, what rule must we check first
KingHarem16
KingHarem1611mo ago
so if the shipment date is due, then if the punctual flag is true then order the records with the same conditions in a ascending order by the shipment. If the shipment date is not due only by the shipment date in ascending order
Pobiega
Pobiega11mo ago
we can't really do if here but we both agree that if the item is due or not is the most important thing so lets start by ordering on that
var sorted = list
.OrderByDescending(x => IsDue(x))
.ToList();
var sorted = list
.OrderByDescending(x => IsDue(x))
.ToList();
IsDue is just a local function: bool IsDue(Shipment x) => x.DesiredShipmentDate < DateTime.Now;
KingHarem16
KingHarem1611mo ago
ok alright
Pobiega
Pobiega11mo ago
ok, so now its listing all the items that are due first great
Due date is 2023-08-31 13:02:34
Shipment { DesiredShipmentDate = 2023-08-30 13:02:34, Punctual = True }
Shipment { DesiredShipmentDate = 2023-08-26 13:02:34, Punctual = False }
Shipment { DesiredShipmentDate = 2023-08-22 13:02:34, Punctual = True }
Shipment { DesiredShipmentDate = 2023-08-29 13:02:34, Punctual = False }
Shipment { DesiredShipmentDate = 2023-09-06 13:02:34, Punctual = False }
Shipment { DesiredShipmentDate = 2023-09-02 14:02:34, Punctual = True }
Shipment { DesiredShipmentDate = 2023-09-02 13:02:34, Punctual = False }
Shipment { DesiredShipmentDate = 2023-09-03 13:02:34, Punctual = False }
Shipment { DesiredShipmentDate = 2023-09-03 13:02:34, Punctual = True }
Due date is 2023-08-31 13:02:34
Shipment { DesiredShipmentDate = 2023-08-30 13:02:34, Punctual = True }
Shipment { DesiredShipmentDate = 2023-08-26 13:02:34, Punctual = False }
Shipment { DesiredShipmentDate = 2023-08-22 13:02:34, Punctual = True }
Shipment { DesiredShipmentDate = 2023-08-29 13:02:34, Punctual = False }
Shipment { DesiredShipmentDate = 2023-09-06 13:02:34, Punctual = False }
Shipment { DesiredShipmentDate = 2023-09-02 14:02:34, Punctual = True }
Shipment { DesiredShipmentDate = 2023-09-02 13:02:34, Punctual = False }
Shipment { DesiredShipmentDate = 2023-09-03 13:02:34, Punctual = False }
Shipment { DesiredShipmentDate = 2023-09-03 13:02:34, Punctual = True }
but it ignores punctual, and the date itself so, lets make it respect the date. Any ideas on how we would do that?
KingHarem16
KingHarem1611mo ago
i would orderBy(x => x.DesiredShipmentDate)
Pobiega
Pobiega11mo ago
Pobiega
Pobiega11mo ago
uh oh. Lets follow the advice.
var sorted = list
.OrderByDescending(x => IsDue(x))
.ThenBy(x => x.DesiredShipmentDate)
.ToList();
var sorted = list
.OrderByDescending(x => IsDue(x))
.ThenBy(x => x.DesiredShipmentDate)
.ToList();
Due date is 2023-08-31 13:05:59
Shipment { DesiredShipmentDate = 2023-08-22 13:05:59, Punctual = True }
Shipment { DesiredShipmentDate = 2023-08-26 13:05:59, Punctual = False }
Shipment { DesiredShipmentDate = 2023-08-29 13:05:59, Punctual = False }
Shipment { DesiredShipmentDate = 2023-08-30 13:05:59, Punctual = True }
Shipment { DesiredShipmentDate = 2023-09-02 13:05:59, Punctual = False }
Shipment { DesiredShipmentDate = 2023-09-02 14:05:59, Punctual = True }
Shipment { DesiredShipmentDate = 2023-09-03 13:05:59, Punctual = False }
Shipment { DesiredShipmentDate = 2023-09-03 13:05:59, Punctual = True }
Shipment { DesiredShipmentDate = 2023-09-06 13:05:59, Punctual = False }
Due date is 2023-08-31 13:05:59
Shipment { DesiredShipmentDate = 2023-08-22 13:05:59, Punctual = True }
Shipment { DesiredShipmentDate = 2023-08-26 13:05:59, Punctual = False }
Shipment { DesiredShipmentDate = 2023-08-29 13:05:59, Punctual = False }
Shipment { DesiredShipmentDate = 2023-08-30 13:05:59, Punctual = True }
Shipment { DesiredShipmentDate = 2023-09-02 13:05:59, Punctual = False }
Shipment { DesiredShipmentDate = 2023-09-02 14:05:59, Punctual = True }
Shipment { DesiredShipmentDate = 2023-09-03 13:05:59, Punctual = False }
Shipment { DesiredShipmentDate = 2023-09-03 13:05:59, Punctual = True }
Shipment { DesiredShipmentDate = 2023-09-06 13:05:59, Punctual = False }
ok, that looks better! but it still doesnt care about punctual how do we fix that
KingHarem16
KingHarem1611mo ago
i would add another .ThenByDescending(x => x.Punctual)
Pobiega
Pobiega11mo ago
Lets give it a spin where would you add it, just to be clear?
KingHarem16
KingHarem1611mo ago
before the thenBy(x => x.DesiredShipmentDate)
Pobiega
Pobiega11mo ago
ok
Due date is 2023-08-31 13:10:14
Shipment { DesiredShipmentDate = 2023-08-22 13:10:14, Punctual = True }
Shipment { DesiredShipmentDate = 2023-08-30 13:10:14, Punctual = True }
Shipment { DesiredShipmentDate = 2023-08-26 13:10:14, Punctual = False }
Shipment { DesiredShipmentDate = 2023-08-29 13:10:14, Punctual = False }
--- Due date here ---
Shipment { DesiredShipmentDate = 2023-09-02 14:10:14, Punctual = True }
Shipment { DesiredShipmentDate = 2023-09-03 13:10:14, Punctual = True }
Shipment { DesiredShipmentDate = 2023-09-02 13:10:14, Punctual = False }
Shipment { DesiredShipmentDate = 2023-09-03 13:10:14, Punctual = False }
Shipment { DesiredShipmentDate = 2023-09-06 13:10:14, Punctual = False }
Due date is 2023-08-31 13:10:14
Shipment { DesiredShipmentDate = 2023-08-22 13:10:14, Punctual = True }
Shipment { DesiredShipmentDate = 2023-08-30 13:10:14, Punctual = True }
Shipment { DesiredShipmentDate = 2023-08-26 13:10:14, Punctual = False }
Shipment { DesiredShipmentDate = 2023-08-29 13:10:14, Punctual = False }
--- Due date here ---
Shipment { DesiredShipmentDate = 2023-09-02 14:10:14, Punctual = True }
Shipment { DesiredShipmentDate = 2023-09-03 13:10:14, Punctual = True }
Shipment { DesiredShipmentDate = 2023-09-02 13:10:14, Punctual = False }
Shipment { DesiredShipmentDate = 2023-09-03 13:10:14, Punctual = False }
Shipment { DesiredShipmentDate = 2023-09-06 13:10:14, Punctual = False }
looks good at first, but when the due date isn't passed we have some issues can you figure out why?
KingHarem16
KingHarem1611mo ago
we dont order after the DesiredShipmentDate after the dueDate
Pobiega
Pobiega11mo ago
no we do, its just that our sort order is pretty well defined we care about due date, then punctual, then date so items that are due go first. then punctual, then by date... so, that causes issues because we dont care about punctual if the item is not due
KingHarem16
KingHarem1611mo ago
yep
Pobiega
Pobiega11mo ago
so, how do we fix it? as a reminder, this is our current code:
var sorted = list
.OrderByDescending(x => IsDue(x))
.ThenBy(x => x.DesiredShipmentDate)
.ToList();
var sorted = list
.OrderByDescending(x => IsDue(x))
.ThenBy(x => x.DesiredShipmentDate)
.ToList();
note that I dont have punctual in here
KingHarem16
KingHarem1611mo ago
var sorted = list .OrderByDescending(x => IsDue(x)) .ThenBy(x => x.DesiredShipmentDate) .ToList(); wait
Pobiega
Pobiega11mo ago
I'll give you a hint, we don't need to add any more lines. Only modify one of the lines
KingHarem16
KingHarem1611mo ago
ok now im lost xD var sorted = list .OrderByDescending(x => IsDue(x) && x.Punctual) .ThenBy(x => x.DesiredShipmentDate) .ToList(); ??
Pobiega
Pobiega11mo ago
yes!
KingHarem16
KingHarem1611mo ago
lol
Pobiega
Pobiega11mo ago
we only care about punctual if its due so isDue(x) && x.Punctual actually works great technically, it only works because of the later sorting by date too since the items that are due but not punctual should come last, and they do because of this
KingHarem16
KingHarem1611mo ago
ah very nice
Pobiega
Pobiega11mo ago
you could make it three statements: due due and punctual date but since the end result of all three rules applied together is the same, I didnt bother with that
KingHarem16
KingHarem1611mo ago
yeah before i had a approach where i didnt even check if the date is due because i thought it wouldnt be necessary bc im already sorting after a descending date and the due one would be at the start to begin with
Pobiega
Pobiega11mo ago
yep, that was my first approach too but I quickly realized that I need to know if its due or not since only when its due should Punctual matter
KingHarem16
KingHarem1611mo ago
yep and i missed that point completly but really great stuff man really appreciate the help and the educational way u showed it to me
Pobiega
Pobiega11mo ago
np here is my full source
public static class Program
{
public static void Run()
{
var list = new List<Shipment>
{
new(DateTime.Now.AddDays(6), false),
new(DateTime.Now.AddDays(2).AddHours(1), true),
new(DateTime.Now.AddDays(-1), true),
new(DateTime.Now.AddDays(-5), false),
new(DateTime.Now.AddDays(-9), true),
new(DateTime.Now.AddDays(-2), false),
new(DateTime.Now.AddDays(2), false),
new(DateTime.Now.AddDays(3), false),
new(DateTime.Now.AddDays(3), true),
};

bool IsDue(Shipment x) => x.DesiredShipmentDate < DateTime.Now;

var sorted = list
.OrderByDescending(x => IsDue(x) && x.Punctual)
.ThenBy(x => x.DesiredShipmentDate)
.ToList();

Console.WriteLine($"Due date is {DateTime.Now}");
var dueDatePassed = false;
foreach (var shipment in sorted)
{
if (!IsDue(shipment) && !dueDatePassed)
{
Console.WriteLine("--- Due date here ---");
dueDatePassed = true;
}

Console.WriteLine(shipment);
}
}
}

public record Shipment(DateTime DesiredShipmentDate, bool Punctual);
public static class Program
{
public static void Run()
{
var list = new List<Shipment>
{
new(DateTime.Now.AddDays(6), false),
new(DateTime.Now.AddDays(2).AddHours(1), true),
new(DateTime.Now.AddDays(-1), true),
new(DateTime.Now.AddDays(-5), false),
new(DateTime.Now.AddDays(-9), true),
new(DateTime.Now.AddDays(-2), false),
new(DateTime.Now.AddDays(2), false),
new(DateTime.Now.AddDays(3), false),
new(DateTime.Now.AddDays(3), true),
};

bool IsDue(Shipment x) => x.DesiredShipmentDate < DateTime.Now;

var sorted = list
.OrderByDescending(x => IsDue(x) && x.Punctual)
.ThenBy(x => x.DesiredShipmentDate)
.ToList();

Console.WriteLine($"Due date is {DateTime.Now}");
var dueDatePassed = false;
foreach (var shipment in sorted)
{
if (!IsDue(shipment) && !dueDatePassed)
{
Console.WriteLine("--- Due date here ---");
dueDatePassed = true;
}

Console.WriteLine(shipment);
}
}
}

public record Shipment(DateTime DesiredShipmentDate, bool Punctual);
If you feel that you're happy and have no further questions, feel free to $close this thread
MODiX
MODiX11mo ago
Use the /close command to mark a forum thread as answered
KingHarem16
KingHarem1611mo ago
ok will do