Reputation: 33
I have two lists - a Guest list and a VIP list. I need to sort the Guest list so that if it contains the first person on the VIP list they go to the top of the list, and so on. After the VIP list is exhausted the rest of the Guest list remains in original order. The ordering has to use both the first name and last name. I've done this using List and foreach statements, but it seems there should be a more elegant way.
Is there a simpler, more modern way to do this sort?
class Guest
{
public int NumberInParty { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
class VIP
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
class TrackedGuest
{
public Guest guest;
public bool isTaken;
public TrackedGuest(Guest g)
{
this.guest = g;
isTaken = false;
}
}
static void Main(string[] args)
{
List<Guest> guests = new List<Guest>();
guests.Add(new Guest { FirstName = "Rob", LastName = "Carson", NumberInParty = 5 });
guests.Add(new Guest { FirstName = "George", LastName = "Waverly", NumberInParty = 3 });
guests.Add(new Guest { FirstName = "Pete", LastName = "Spacely", NumberInParty = 2 });
guests.Add(new Guest { FirstName = "George", LastName = "Jetson", NumberInParty = 6 });
guests.Add(new Guest { FirstName = "Cosmo", LastName = "Spacely", NumberInParty = 2 });
List<VIP> vips = new List<VIP>();
vips.Add(new VIP { FirstName = "George", LastName = "Jetson" });
vips.Add(new VIP { FirstName = "Cosmo", LastName = "Spacely" });
List<TrackedGuest> TrackedGuests = new List<TrackedGuest>();
foreach (Guest g in guests)
{
TrackedGuests.Add(new TrackedGuest(g));
}
List<Guest>SortedGuests = new List<Guest>();
// Copy each guest on the VIP list in order
foreach (VIP vip in vips)
{
foreach (TrackedGuest tGuest in TrackedGuests)
{
if (
(tGuest.isTaken == false) &&
(vip.FirstName == tGuest.guest.FirstName) &&
(vip.LastName == tGuest.guest.LastName)
)
{
SortedGuests.Add(tGuest.guest);
tGuest.isTaken = true;
}
}
}
// Process the rest of the guests
if (SortedGuests.Count < guests.Count)
{
foreach (TrackedGuest tGuest in TrackedGuests)
{
if (tGuest.isTaken == false)
{
SortedGuests.Add(tGuest.guest);
tGuest.isTaken = true;
}
}
}
foreach (Guest guest in SortedGuests)
{
Console.WriteLine(guest.FirstName + " " + guest.LastName + ": " + guest.NumberInParty + " in party.");
}
Console.ReadLine();
}
Upvotes: 3
Views: 138
Reputation: 2017
var sorted = new List<Guest>();
var guestvips = from g in guests
from v in vips.Where(vip => vip.FirstName == g.FirstName && vip.LastName == g.LastName).DefaultIfEmpty()
where v != null
select g;
var guestsimple = from g in guests
from v in vips.Where(vip => vip.FirstName == g.FirstName && vip.LastName == g.LastName).DefaultIfEmpty()
where v == null
select g;
sorted.AddRange(guestvips.Concat(guestsimple));
This code 'left join' guests on vips two times. In first case it takes those guests, which has equal vip and second those, which has no equal vip. First case can be rewriten with 'join' keyword actually.
Upvotes: 4
Reputation: 125650
// dictionary to easily get vips order
// uses anonymous types, to get value equality for free
var vipsOrder = vips.Select((v, i) => new { v, i })
.ToDictionary(x => new { x.v.FirstName, x.v.LastName },
x => x.i);
// sort first by order taken from vipsOrder and then by name
var sortedGuests = (from g in guests
let info = new { g.FirstName, g.LastName }
let oorder
= vipsOrder.ContainsKey(info)
? vipsOrder[info] : vips.Count
orderby oorder, info.FirstName, info.LastName
select g).ToList();
Upvotes: 0