需要更好的方法将一个列表与另一个列表进行排序

3
我有两个列表 - 客人列表和VIP列表。我需要对客人列表进行排序,以便如果其包含VIP列表中的第一个人,则将他们置于列表顶部,依此类推。在VIP列表用尽后,客人列表的其余部分保持原始顺序。排序必须使用名字和姓氏。我已经使用List和foreach语句完成了这个任务,但似乎应该有更优雅的方法。
是否有更简单、更现代的方法来进行这种排序?
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();
}

3
建议您将此内容发布在 Code Review 而不是 Stack Overflow 上。前者旨在为正在工作但可能需要改进的代码进行同行评审。请注意,这里只涉及对一组代码的评审,而非其他问题。 - Jonathon Reinhart
1
我已经有一段时间没有写C#了,但我相信您可以使用哈希表来管理VIP列表,并向您的Guest类添加一个值(可能称为VIP)来指示它是VIP。然后,在构建Guest列表时,在哈希表中查找名称,如果存在,则设置Guest类中的值以指示它。然后,首先按VIP字段对Guest类进行排序,其次按名称作为辅助键。看起来这将是一种简单直接的方法,需要更少的代码。 - RegularExpression
尝试使用LINQ;请参考此链接:https://dev59.com/o2865IYBdhLWcg3wLber - Ujjwal
2个回答

4
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));

这段代码在左连接中两次使用了'guests'和'vips'。第一个情况下,它会选择那些具有相等vip的客人,而第二个情况下则是选择没有相等vip的客人。实际上,第一个情况可以使用'join'关键字进行重写。


这是正确的答案,但可以通过1-2个句子来解释它的作用以进一步完善。在SO上,仅仅抛出一个代码片段并不是首选的回答方式。 - BigM
我认为这是一个几乎完美的答案。直截了当,没有废话。 - RegularExpression
这个答案最接近我所寻找的类型,但我从所有的答案和评论中学到了很多。谢谢! - Bob Williams

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接