【问题标题】:Is sorting a list the best solution?排序列表是最好的解决方案吗?
【发布时间】:2013-03-01 10:25:41
【问题描述】:

我正在为学校做一个项目,并试图决定我应该如何去做。

这是一个餐厅模拟。我生成一张桌子和等候方的随机列表。我随机安排了一些派对,有些派对没有在等候名单上。我希望有保留的各方拥有第一优先权。

是否对列表进行排序,以便所有有预订的各方都在一端,而没有另一端的一方是解决这个问题的好方法?

然后我可以只评估列表,看看派对是否适合在桌子上,然后让他们入座或继续下一个派对。还是有更聪明的方法来解决这个问题?任何意见表示赞赏!

【问题讨论】:

  • 循环一次并处理预订,然后再次处理其他所有人。您需要的更像是过滤聚会的集合,而不是排序——尽管排序当然可以划分列表并使过滤变得非常容易,但这只是达到目的的一种手段,可能并不值得。
  • 为了让餐厅更有效率,您会希望它的预订量永远不会超过座位数。预订应该意味着该人始终在餐桌旁获得座位,无论他们的顺序如何。如果预订数量 = 座位数量,那么您不关心其他列表。但是,如果预订数量
  • 按保留对它们进行排序似乎是合理的。我会按照你的想法运行,看看它会把你带到哪里。
  • @dash 您可能需要更多的聪明才智,而不仅仅是到达顺序。如果队列前面有一个 4 人的聚会,但您有一张 2 人的空桌,您需要进一步查看。
  • @JRoughan 同意,但永远不需要对有保留的人员列表进行排序;只需要把人分成两组,有保留和没有保留。然后,您需要做的唯一排序是在没有预订的情况下对组进行排序,并且在这种情况下,您希望 take 与您拥有的空座位(桌子)数量相匹配的第一方,按到达顺序排序.在这种情况下,列表可能不是最好的构造;由 Party 对象组成的队列可能会更好,因为您可以立即删除 Reservation = true 的 Party。

标签: c# list sorting


【解决方案1】:
var groupedParties = parties.GroupBy(p => p.HasReservation);

这是迄今为止我看到的最干净的方式。你会得到一个包含两个组的列表,一个包含没有的缔约方,一个包含有保留的缔约方。您现在可以分别处理不同类型的等候派对的座位。

编辑

static void Main(string[] args)
{
    GenerateRandomDataSomehow();
    var groupedParties = _parties.GroupBy(p => p.HasReservation)
    SeatParty(groupedParties.FirstOrDefault(g => g.Key == true));
    SeatParty(groupedParties.FirstOrDefault(g => g.Key == false));
}

private static void SeatParty(IEnumerable<Party> partyGroup)
{
    if (partyGroup == null) return;

    foreach (var party in partyGroup.OrderBy(p => p.ArrivalTime))
    {
        var properTable = _tables.FirstOrDefault(t => t.SeatsCount == party.PersonsCount &&
                                                      t.Party == null);
        if (properTable == null) continue;
        properTable.Party = party;
    }
}

这是一个非常简单的实现,带有更多的 LINQ。选择标准需要适当扩展。在此表中,如果没有其他方坐在此表上,则将其评估为“适当”,但如果人数准确,则相应表的座位数。如果找不到合适的表,则跳过该组。

【讨论】:

    【解决方案2】:

    您可能希望使用 Queue 或类似队列的构造而不是 List 来为您的餐厅建模,并采用不同的方法。这样,您将按照人员到达的顺序存储人员,因此无需进行排序。

    将人员分组到一个 Party 对象中。当派对到达时,您可以将它们添加到队列中。然后,您可以查看队列,如果一方有预订,您可以将其从队列中删除并将其发送到他们的餐桌。如果该派对没有预订,那么您检查是否有适合该大小的派对的桌子,如果有,则将该派对从队列中移除。

    否则,您可以等到表格可用;当该事件发生时,您可以再次排队,寻找适合餐桌大小的派对。您还可以检查队列此时是否包含有预订的派对,这意味着他们优先 - 使用Queue.First(x =&gt; x.HasReservation &amp;&amp; x.Size &lt;= Table.Places) 从队列中挑选第一批有预订且可以就座的人* *。否则,Queue.First(x =&gt; x.Size &lt;= Table.Places) 将为您提供排队等候的第一批人。

    使用队列的优点是不需要排序,您可以按照到达的顺序处理多方人员,优先考虑有预订的人员。

    您在两个点检查队列:

    1. 当人们到达时(他们是否已预订,是否有空位)
    2. 当有空位时 - 首先在队列中查找已预订并能够就座的人;如果没有匹配,则从队列中取出与桌子大小匹配(或可以容纳在桌子上)的第一组人

    这是一个很好的起点。

    更新

    正如您所发现的,您无法从队列中间移除项目。这是因为队列是先进先出 (FIFO) [与堆栈相反,堆栈是后进先出 - LIFO]。为了避免排序,您可以使用具有类似语义的队列的 List - this answer 中有一个很好的示例。

    ** 这里还有一个有趣的排队问题——效率问题。如果有 4 个位置的桌子可用,你会怎么做?把它给第一个到达的适合在桌子上的一方,或者给它在队列中适合在桌子上的最大的一方。显然,第一个选项最适合客户服务,因为您坐着等待时间最长的人,但第二个选项可以最大化您的利润,因为您可以更充分地利用桌子:-)

    【讨论】:

    • 有趣的是,我现在对队列不熟悉,我正在对列表进行排序,看看如何让它发挥作用。虽然您解释它的方式似乎更适合我必须尝试使用​​队列的情况,但谢谢。
    • @dsquaredtech 队列类似于现实生活中的人群队列;当多人到达餐厅时会发生什么:-) 祝你的任务好运,最重要的是,玩得开心:-D
    • 我在排序列表和使用队列方面取得了巨大成功。我认为队列是最聪明的方法,我正在改变这个答案。谢谢破折号!
    • 最后我没有成功使用队列,因为我可以使用 FirstOrDefault 从队列中提取正确的值,但我无法将我需要的内容出列到目前还没有方法可以将特定的东西出列我能找到。
    • @dsquaredtech 我希望你会问这个问题!队列是 FIFO(先进先出与 Stack 比较,后者是 LIFO - 后进先出),现在您已经看到了删除不在队列顶部的项目的问题(它不是为此而设计的)。您可以维护一些队列(保留队列、开放队列,以及针对每个派对规模的更多队列),或者您可以使用列表但强制执行队列类似语义 - 例如,请参阅 stackoverflow.com/questions/1594375/…。无论哪种方式,不,您不需要对列表进行排序:-)
    【解决方案3】:

    如果您想对列表进行排序:

    使用Enumerable.OrderByDescendingThenByDescending

    var ordered = parties.OrderByDescending(p => p.HasReservation)
                         .ThenByDescending(p => p.PersonCount);
    // if you want a new list use ordered.ToList()
    foreach(var party in ordered)
    {
        // ...
    }
    

    如果您想对原始列表进行排序,您可以使用 List&lt;T&gt;.Sort 和自定义委托:

    parties.Sort((p1, p2) =>
    {
        if (p1.HasReservation != p2.HasReservation)
            return p1.HasReservation ? 1 : -1;
        else
            return p1.PersonCount.CompareTo(p2.PersonCount);
    });
    

    【讨论】:

    • 非常感谢,我认为这非常适合这种情况。
    【解决方案4】:

    在这种情况下,使用System.Linq 可能是您对列表进行排序的最佳选择。

    类似:

    var sorted = tables.OrderByDescending(o => o.IsReserved);
    

    【讨论】:

      【解决方案5】:

      我会简单地使用两个队列(假设您的各方由称为Party 的类型表示。适当地更改类型):

      Queue<Party> withReservation = new Queue<Party>();
      Queue<Party> withoutReservation = new Queue<Party>();
      

      您可以像这样将派对添加到队列中:

      if (party has reservation) { // (condition in pseudo code)
          withReservation.Enqueue(party);
      } else {
          withoutReservation.Enqueue(party);
      }
      

      你会像这样参加派对:

      if (withReservation.Count > 0) {
          Seat(withReservation.Dequeue());
      } else if (withoutReservation.Count > 0) {
          Seat(withoutReservation.Dequeue());
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2012-10-11
        • 1970-01-01
        • 1970-01-01
        • 2016-10-17
        • 1970-01-01
        • 2010-11-08
        • 2014-03-24
        相关资源
        最近更新 更多