C#使用groupby和where在哪里搜索列表

时间:2018-05-25 18:36:55

标签: c# linq lambda

我正在尝试搜索按插槽号搜索多个客户的空时段。如果该客户有时间,则应返回找到的第一个客户。

示例数据(每个客户都有一个唯一的插槽号)

customer 1: slotnumber 0, time 0
customer 1: slotnumber 0, time 1
customer 1: slotnumber 0, time 2
customer 1: slotnumber 0, time 4

customer 2: slotnumber 1, time 0
customer 2: slotnumber 1, time 1

我有以下课程:

public class CustomerSlot
{
    public int customerid { get; set; }  
    public int slotnumber { get; set; }  
    public int time { get; set; }
}

然后我有一个customersslots列表:

List<CustomerSlot> lstCustomerSlots = new List<CustomerSlot>();

现在假设我想使用上述数据找到时间3可用的第一个插槽。

这是我需要帮助的地方。我没有正确的语法来由客户分组并返回具有该时间段的客户:

CustomerSlot timeSpaceFound = lstCustomerSlots
                                  .Where(t => t.time != 3)   // Search for time 3
                                  .GroupBy(c => c.customerid) // Search an entire customer
                                  .OrderBy(c => c.customerid) // Start searching by the order of first customerid
                                  .FirstOrDefault();

任何帮助设置上述lambda将不胜感激。没有找到任何在线搜索解决方案的示例。谢谢。

2 个答案:

答案 0 :(得分:1)

您需要按客户对时间进行分组,然后找到没有时间段的最低客户ID:

var timeSpaceFound = lstCustomerSlots.GroupBy(c => c.customerid)
                                     .Where(cg => !cg.Any(c => c.time == 3))
                                     .OrderBy(cg => cg.Key)
                                     .FirstOrDefault()
                                     ?.Key;

我更喜欢使用扩展方法MinBy

public static T MinBy<T, TKey>(this IEnumerable<T> src, Func<T,TKey> keySelector, Comparer<TKey> keyComparer) => src.Aggregate((a, b) => keyComparer.Compare(keySelector(a), keySelector(b)) < 0 ? a : b);
public static T MinBy<T, TKey>(this IEnumerable<T> src, Func<T,TKey> keySelector) => src.Aggregate((a, b) => Comparer<TKey>.Default.Compare(keySelector(a), keySelector(b)) < 0 ? a : b);

然后你就做了

var timeSpaceFound = lstCustomerSlots.GroupBy(c => c.customerid)
                                     .Where(cg => !cg.Any(c => c.time == 4))
                                     .MinBy(cg => cg.Key)
                                     ?.Key;

这应该更有效率,因为Aggregate只能通过列表一次。

如果您希望收到CustomerSlot而不是customerid,则需要获得该组中的第一个(除非您需要特定的时间段):

var timeSpaceFound = lstCustomerSlots.GroupBy(c => c.customerid)
                                     .Where(cg => !cg.Any(c => c.time == 4))
                                     .MinBy(cg => cg.Key)
                                     .FirstOrDefault();

答案 1 :(得分:1)

如果我理解正确,您希望从列表中选择3已经没有任何时段条目的第一个客户。

CustomerSlot timeSpaceFound = lstCustomerSlots
                                  .GroupBy(c => c.customerid) // Group entries by customer
                                  .Where(g => g.All(c => c.time != 3)) // Remove all groups that have a time entry of 3
                                  .OrderBy(g => g.Key) // Start searching by the order of first customerid
                                  .FirstOrDefault() // Select the first group
                                  ?.FirstOrDefault(); // Select the first CustomerSlot entry in the group.