简体   繁体   中英

Need better way to sort one list against another list

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();
}
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.

// 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();

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM