简体   繁体   English

如何获得linq中最高和最低价格项目的总和

[英]How to get the sum of the volume of highest and lowest priced items in linq

The actual query I am trying to write is slightly trickier than the title suggests. 我试图写的实际查询比标题所暗示的要复杂一些。 I have a list of orders like such: List<Order> , an order looks like this: 我有一个这样的订单列表: List<Order> ,订单如下:

public class Order
{
    private StockCodes _stockCode;
    private bool _bidSide;
    private int _volume;
    private decimal _price;
}

I need to publish the best bid price and volume and the best sell price and volume given a specific stock code. 我需要在给定特定股票代码的情况下公布最佳买入价和成交量以及最佳卖出价和成交量。 The best bid price is defined as the HIGHEST price where bidSide is true. 最佳报价定义为bidSide为true的最高价格。 The best sell price is defined as the LOWEST price where bidSide is false. 最佳卖价定义为bidSide为false的最低价格。

For example given the following data for stock code "ABC": 例如,给出股票代码“ABC”的以下数据:

 { bidSide: true, volume: 25, price: 25  }
 { bidSide: true, volume: 25, price: 25  }
 { bidSide: true, volume: 25, price: 5  }

 { bidSide: false, volume: 100, price: 1  }
 { bidSide: false, volume: 50, price: 2}
 { bidSide: false, volume: 75, price: 8 }

Best bid: price 25, volume 50 (since there are 2 orders at the highest price) Best sell: price 1, volume 100 (since there is just 1 order at the lowest price) 最佳出价:价格25,成交量50(因为最高价格有2个订单)最畅销:价格1,成交量100(因为最低价格只有1个订单)

Lastly, I need to account for when there are no bid or sell orders. 最后,我需要考虑什么时候没有买入或卖出订单。 Efficiency is of high priority, so If I am able to do this in one linq statement that would be preferred. 效率是高优先级,所以如果我能够在一个首选的linq语句中这样做。

To do this efficiently, you really only want to iterate over the data once. 要有效地执行此操作,您实际上只想迭代数据一次。 Unfortunately, that makes it a real pain to implement with LINQ, as there's quite a lot of work to do. 不幸的是,这使用LINQ实现真正的痛苦,因为还有很多工作要做。

Personally I would suggest that you don't do this with LINQ - you could implement it with Aggregate , but it wouldn't be terribly pleasant. 我个人建议你不要用LINQ做这个 - 你可以Aggregate实现它,但它不会非常令人愉快。 It's not too bad with a simple foreach loop though. 虽然简单的foreach循环并不算太糟糕。 Something like: 就像是:

int buyVolume = -1;
int sellVolume = -1;
decimal buyPrice = decimal.MinValue;
decimal sellPrice = decimal.MaxValue;

foreach (var order in orders)
{
    if (order.bidSide)
    {
        if (order.Price > buyPrice)
        {
            buyPrice = order.Price;
            buyVolume = order.Volume;
        }
        else if (order.Price == buyPrice)
        {
            buyVolume += order.Volume;
        }
    }
    else
    {
        if (order.Price < sellPrice)
        {
            sellPrice = order.Price;
            sellVolume = order.Volume;
        }
        else if (order.Price == sellPrice)
        {
            sellVolume += order.Volume;
        }
    }
}

// Check sellVolume == -1 to verify whether we've seen any sale orders
// Check buyVolume == -1 to verify whether we've seen any buy orders
// Use buyPrice/buyVolume and sellPrice/sellVolume otherwise

Doing it as efficiently as possible in LINQ would effectively mean putting all that logic in the loop into a function to pass into Aggregate - and you'd probably want to create a custom value type to hold the four values, to avoid creating more objects than you need to. 在LINQ中尽可能高效地执行它实际上意味着将循环中的所有逻辑放入一个函数以传递到Aggregate - 并且您可能想要创建一个自定义值类型来保存四个值,以避免创建比你需要。 That may be overkill, but you did say you wanted it as efficient as possible... 可能有点矫枉过正,但你确实说过你希望它尽可能高效......

HIGHEST = orders.Max(x => x.bidSide ? x.price : (decimal?)null) ?? 0M

Similar for LOWEST. 类似于LOWEST。

Linq2SQL will not convert this into an efficient query, unfortunately. 不幸的是,Linq2SQL不会将其转换为有效的查询。 It will execute in one single query, but the data will be scanned once per Max operation (in your case two times: HIGHEST and LOWEST). 它将在一个查询中执行,但每次Max操作将扫描一次数据(在您的情况下,两次:HIGHEST和LOWEST)。 In raw SQL you can do this in one pass over the data. 在原始SQL中,您可以在一次传递数据时执行此操作。

This could do LINQ wise... 这可以做LINQ明智的......

var bids = (from o in orders
                where o.StockCode == "ABC" && o.BidSide == true
                group o by o.Price)
                .OrderByDescending(g => g.Key)
                .FirstOrDefault();
var bidVolume = bids != null ? new Order { Price = bids.Key, Volume = bids.Sum(g => g.Volume) } : null;

var sells = (from o in orders
                where o.StockCode == "ABC" && o.BidSide == false
                group o by o.Price)
                .OrderBy(g => g.Key)
                .FirstOrDefault();
var sellVolume = sells != null ? new Order { Price = sells.Key, Volume = sells.Sum(g => g.Volume) } : null;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM