【问题标题】:How to combine mulitiple LINQ to objects requests into single one如何将多个 LINQ to 对象请求组合成一个
【发布时间】:2015-08-08 12:40:50
【问题描述】:

我想将 GetCurrentAuction 重写为单个 LINQ 请求:

private AuctionInfo GetCurrentAuction()
    {
        var auctions = Auctions.List().ToList();
        var liveAuction = auctions
            .Where(AuctionIsLive)
            .OrderBy(a => a.StartDate)
            .FirstOrDefault();

        if (liveAuction != null)
        {
            return liveAuction;
        }

        var openAuction = auctions
            .Where(AuctionIsOpen)
            .OrderBy(a => a.StartDate)
            .FirstOrDefault();

        if (openAuction != null)
        {
            return openAuction;
        }

        // next upcoming auction
        return auctions
            .Where(a => a.StartDate >= DateTime.UtcNow)
            .OrderBy(a => a.StartDate)
            .FirstOrDefault();
    }

    private bool AuctionIsLive(AuctionInfo auction)
    {
        // WorkflowStage is int
        return auction.WorkflowStage == LIVE_WORKFLOW_STAGE;
    }

    private bool AuctionIsOpen(AuctionInfo auction)
    {
        return auction.WorkflowStage == OPEN_WORKFLOW_STAGE;
    }

有人可以建议如何实现这一目标吗?看起来使用 auctions.GroupBy(a => a.WorkflowStage) 并没有让我更接近解决方案。

【问题讨论】:

  • 我不确定您现有的代码是否一定正确。您会搜索最早的(所有历史上的)“实时”拍卖和最早的“公开”拍卖,如果两者都没有找到,则中止。然后,您对最早的 upcoming/future 拍卖进行第三次搜索,无论它是“Live”还是“Open”(基本上忽略了您之前对“Live”和“Open”的搜索)并返回它.这是正确的吗?
  • @ChrisSinclair 如果没有任何现场或公开拍卖,我将执行“即将举行的拍卖”查询的唯一方法
  • 在最好的情况下,我只执行单个查询(找到实时拍卖并返回它),在最坏的情况下 3
  • -1 你需要告诉 use 你使用的是什么类型的 Linq? Linq 到 SQL、到 EF、到对象等?请标记您使用的类型。
  • Auctions.List() 返回什么?我认为您的主要问题是您将所有拍卖都拖入内存。这应该首先处理。

标签: c# linq linq-to-objects


【解决方案1】:

您可以通过订购来表明偏好 - 类似于:

return
  Auctions.List().ToList()  //--> ToList() not needed here?
  .Where
  ( a =>
    AuctionIsLive(a) ||
    AuctionIsOpen(a) ||
    a.StartDate >= DateTime.UtcNow
  )
  .OrderBy
  ( a => 
    AuctionIsLive( a ) ? 0 :
    AuctionIsOpen( a ) ? 1 : 2
  )
  .ThenBy( a => a.StartDate )
  .FirstOrDefaut();

【讨论】:

  • 击败我,但如果没有现场或公开拍卖,您将忽略获得下一次即将举行的拍卖的逻辑。我会在 .FirstOrDefault() 之前添加 .ThenBy(a => a.StartDate)
  • @Dustin Cleveland - 实际上 - 我有那个(但略有不同),但我把它去掉了,因为 where 子句只包括 live、open 或 in-the-future - 所以,live 是受欢迎的,然后是 open,然后是(仅)未来项目。
  • @Clay 但是拍卖列表可能是无序的,然后我们不会首先采取最早的行动
  • @OleksiiAza - 我现在明白了 - 是的!已编辑答案 - 感谢您和达斯汀
【解决方案2】:

你可以使用非常有用的 ?? (https://msdn.microsoft.com/en-us/library/ms173224.aspx) 运算符并实现:

        var result = auctions.Where(AuctionIsLive).OrderBy( x => x.StartDate).FirstOrDefault() ?? 
            auctions.Where(AuctionIsOpen).OrderBy( x => x.StartDate).FirstOrDefault() ??
            auctions.Where(a => a.StartDate >= DateTime.UtcNow).OrderBy(a => a.StartDate).FirstOrDefault();

        return result;

【讨论】:

  • @funkyCats 这绝对提高了可读性,谢谢。但在最坏的情况下,它会窃取执行多个查询。
  • @EugeneSafronov 请试试这个:var result2 = auctions.OrderBy(x => x.StartDate).FirstOrDefault(x => x.WorkflowStage == LIVE_WORKFLOW_STAGE || x.WorkflowStage == OPEN_WORKFLOW_STAGE || x.StartDate >= DateTime.UtcNow);
【解决方案3】:

这取决于您使用的数据源和 LINQ 提供程序。 例如,如果您使用 LINQ to SQL,则首选的方法是使用Expressions 来节省您的内存并最终得到类似于@fankyCatz 的答案:

return Auctions.Where(a => a.WorkflowStage == LIVE_WORKFLOW_STAGE).OrderBy(x => x.StartDate).FirstOrDefault() ??
        Auctions.Where(a => a.WorkflowStage == OPEN_WORKFLOW_STAGE).OrderBy(x => x.StartDate).FirstOrDefault() ??
        Auctions.Where(a => a.StartDate >= DateTime.UtcNow).OrderBy(a => a.StartDate).FirstOrDefault();

但是,仅使用 LINQ to Objects 我最终会得到类似于@Clay 的答案,只是会提高映射的可读性:

public static Dictionary<int, Func<AuctionInfo, bool>> Presedence = 
            new Dictionary<int, Func<AuctionInfo, bool>>
{
    { 0, a => a.WorkflowStage == LIVE_WORKFLOW_STAGE },
    { 1, a => a.WorkflowStage == OPEN_WORKFLOW_STAGE },
    { 2, a => a.StartDate >= DateTime.UtcNow },
};

//in your GetCurrentAuction()
return Auctions.Where(a => Presedence.Any(p => p.Value(a)))
                .OrderBy(a => Presedence.First(p => p.Value(a)).Key)
                .ThenBy(a => a.StartDate)
                .FirstOrDefault();

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-11
    • 1970-01-01
    • 2018-09-15
    • 2017-07-23
    • 1970-01-01
    • 2012-01-01
    相关资源
    最近更新 更多