使用LINQ在列表中迭代智能方式

时间:2012-12-18 17:48:27

标签: c# list linq-to-objects

我有这个简单的课程:

public class JDEItemLotAvailability
    {
        public string Code { get; set; }
        public int ShortCode { get; set; }
        public string Description { get; set; }
        public string PrimaryUnitCode { get; set; }
        public string BranchPlant { get; set; }
        public string Location { get; set; }
        public string Lot { get; set; }
        public int AvailableQuantity { get; set; }
    }

我的BLL中的这个DAL方法返回它们的列表:

var returnedLotList = _JDE8dal.GetLotAvailabilityAsList(_lot);

我想在返回的列表中执行以下操作,并且我希望以最“优雅”的LINQ方式执行此操作。

我想检查列表中是否有符合特定条件的记录。我想到过这样的事情:

  var query =
      returnedLotList.Where(l => l.AvailableQuantity != 0 && l.BranchPlant == _mcu && l.Location == _locn)
                               .OrderByDescending(l => l.AvailableQuantity);

但我想说,如果上面的查询没有返回结果,我想采取其余列表条目的第一个。

我该怎么做?

3 个答案:

答案 0 :(得分:3)

您可以使用DefaultIfEmpty

//your first query, unaltered
var query =
      returnedLotList.Where(l => l.AvailableQuantity != 0 && l.BranchPlant == _mcu && l.Location == _locn)
                               .OrderByDescending(l => l.AvailableQuantity);

var query2 = query.DefaultIfEmpty(returnedLotList.Take(1));

答案 1 :(得分:0)

您可以制作一个执行此操作的扩展方法:

public static IEnumerable<T> WhereOrFirstOfRest<T>(
    this IEnumerable<T> collection, Func<T, bool> predicate)
{
    var filtered = collection.Where(predicate);

    return filtered.Any() ? filtered : collection.Take(1);
}

此扩展方法的缺点是它多次迭代集合。当您处理流(例如,来自数据库)时,这可能是一个问题。一种更有效的方法如下:

public static IEnumerable<T> WhereOrFirstOfRest<T>(
    this IEnumerable<T> collection, Func<T, bool> predicate)
{
    // Materialize the complete collection.
    collection = collection.ToArray();

    // Filter the collection. ToArray prevents calling the predicate
    // twice for any item.
    var filtered = collection.Where(predicate).ToArray();

    return filtered.Any() ? filtered : collection.Take(1);
}

虽然这可以节省您对数据库的任何可能的额外调用,但这确实会在封面下创建几个新数组。因此,最有效的方法如下:

public static IEnumerable<T> WhereOrFirstOfRest<T>(
    this IEnumerable<T> collection, Func<T, bool> predicate)
{
    T firstItem = default(T);
    bool firstStored = false;
    bool predicateReturnedItems = false;

    foreach (var item in collection)
    {
        if (!firstStored)
        {
            firstItem = item;
            firstStored = true;   
        }

        if (predicate(item))
        {
            yield return item;
            predicateReturnedItems = true;
        }
    }

    if (!predicateReturnedItems && !first)
    {
        yield return firstItem;
    }
}

答案 2 :(得分:0)

我不确定我理解但也许是这样的:

var firstMatch = returnedLotList.FirstOrDefault(l => l.AvailableQuantity != 0 && 
                                                     l.BranchPlant == _mcu && 
                                                     l.Location == _locn);
if (firstMatch != null)
    return firstMatch;
int max = returnedLotList.Max(l => l.AvailableQuantity);
return returnedLotList.First(l => l.AvailableQuantity == max);
  • 如果不匹配,FirstOrDefault将返回null
  • 我认为将查询分开以使其更清楚发生的事情是个好主意。