Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/311.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/list/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 使用LINQ在列表中迭代智能方式_C#_List_Linq To Objects - Fatal编程技术网

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

C# 使用LINQ在列表中迭代智能方式,c#,list,linq-to-objects,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; } publi

我有一个简单的课程:

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; }
    }
my 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);
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);

但是我想说的是,如果上面的查询没有返回结果,那么我希望使用列表中剩余的第一个条目


我如何才能做到这一点?

您可以创建一个扩展方法来实现这一点:

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);
}
公共静态IEnumerable WhereOrFirstOfRest(
此IEnumerable集合(Func谓词)
{
var filtered=collection.Where(谓词);
返回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;
    }
}
公共静态IEnumerable WhereOrFirstOfRest(
此IEnumerable集合(Func谓词)
{
//实现整个集合。
collection=collection.ToArray();
//筛选集合。ToArray阻止调用谓词
//任何项目两次。
var filtered=collection.Where(谓词).ToArray();
返回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;
    }
}
公共静态IEnumerable WhereOrFirstOfRest(
此IEnumerable集合(Func谓词)
{
T firstItem=默认值(T);
bool firstStored=false;
bool predicateReturnedItems=false;
foreach(集合中的var项)
{
如果(!firstStored)
{
firstItem=项目;
firstStored=true;
}
if(谓语(项))
{
收益回报项目;
predicateReturnedItems=true;
}
}
if(!predicateReturnedItems&&!first)
{
第一项收益率;
}
}

您可以使用
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));

我不确定我是否理解,但可能是这样的:

  var query =
      returnedLotList.Where(l => l.AvailableQuantity != 0 && l.BranchPlant == _mcu && l.Location == _locn)
                               .OrderByDescending(l => l.AvailableQuantity);
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
  • 我认为将查询分开是一个好主意,以便更清楚地了解正在发生的事情

“如果上述查询没有返回结果,我想选择列表其余部分中的第一个”。这似乎是一个尴尬的要求。其他开发人员将不断被这个问题绊倒。你确定这是件好事吗?这背后的逻辑是这样的:如果在我想要的特定仓库和地点没有发现大量货物的数量,那么我不介意给我带一份其他记录作为指示。我可以更进一步,做一些处理,而不是第一个,但我想先了解一下基本情况……你怎么知道你得到的记录是“未找到”的记录而不是正确的记录?最好是返回一个空列表,然后用逻辑来处理它。@Bobson:hmm如果我能用LINQ来避免这种过程…@e4rthdog-如果你想对一个“未找到”的记录进行操作,就像它是一个成功的匹配一样,你可以这样做。如果你想知道你没有找到匹配项,你也需要一些标准的逻辑。请注意,如果查询是非空的,它会重复查询多次。一次用于
任何
,一次用于实际结果。当迭代(甚至只获取一个项目)涉及到数据库的往返时,这是一个问题。@Servy:这绝对正确。在我读你的评论之前,我已经在写一个改进版了。我们在同一页:-)你试图同时做很多事。正如我的回答所示,DefaultIfEmpty已经为您完成了大部分这一切,您主要只是重新实现它,并在
Where
中混合使用,而不是单独调用两个现有函数。如果这真的足够让它拥有自己的功能(我怀疑),你仍然可以重复使用这些方法。整个实现可以是
collection.Where(谓词).DefaultIfEmpty(collection.Take(1))给定了您定义的定义。@Servy:请参阅我对您答案的评论。您的代码还将触发第二个查询:-),并查看我的响应。此代码将要求将整个集合拉入内存,甚至是所有不符合筛选条件的项。如果不使用
Where
,则不允许对数据库执行该筛选。请注意,如果筛选列表为空,则会多次迭代查询。一次用于
DefaultIfEmpty
,一次用于运行
Take(1)
。当迭代(即使只获取一个项目)涉及到数据库的往返时,这是一个问题。:-)@史蒂文:实际上,如果
where
过滤了很大一部分内容,这是可取的。首先执行一个查询,在数据库端进行过滤。如果它没有返回任何项目,则对一个项目执行另一个查询。在单个查询中执行此操作的唯一方法是获取所有项,即使是不符合条件的项。这是一个巨大的网络开销。另外,根据问题描述,常见的情况是文件管理器返回一些东西,因此该常见情况仅迭代结果一次。
,其中
将始终在.NET中执行,在这种情况下,不会在数据库中执行。但是,当我们谈论表达式树和使用
Queryable
时,在这种情况下,您是对的,这将是最有效的。@Steven然后多次迭代它的结果足够小(在本文中)以至于无关紧要,因为您只在迭代多次的唯一情况下获取第一项。关键是answe