在 LINQ 中将两个查询转换为一个查询

Transforming two queries into one query in LINQ

我正在计算每个 Pair 来自 List<BacktestResult> 的利润及其交易数量,以及 BacktestResult 对象本身,因为我需要它的属性,例如.打印它们。这就是下面的 foreach 所做的。然后我要接收最大利润的对象。该代码按预期工作,但我想完全在 LINQ 中重新创建它,例如。没有那个丑陋的 Max() 检查。应该 return var bestPair = BacktestResult object of the maximum result.Sum(e => e.ProfitPercentage).

(decimal Max, string Pair) value = (int.MinValue, null);
foreach (var result in data.GroupBy(e => e.Pair)
                           .Select(e => new { Pair = e.Key, Count = e.Count(), Value = e }))
{
    var profitSum = result.Value.Sum(e => e.ProfitPercentage);

    if (profitSum > value.Max)
    {
        value.Max = profitSum;
        value.Pair = result.Pair;
    }
}

public class BacktestResult
{
    public string Pair { get; set; }
    public decimal ProfitPercentage { get; set; }
    public decimal ProfitAbs { get; set; }
    public decimal OpenRate { get; set; }
    public decimal CloseRate { get; set; }
    public DateTime OpenDate { get; set; }
    public DateTime CloseDate { get; set; }
    public decimal OpenFee { get; set; }
    public decimal CloseFee { get; set; }
    public decimal Amount { get; set; }
    public decimal TradeDuration { get; set; }
    public SellType SellReason { get; set; }
}

public static class LinqExtensions
{
    public static T MaxBy<T, R>(this IEnumerable<T> en, Func<T, R> evaluate) where R : IComparable<R>
    {
        return en.Select(t => new Tuple<T, R>(t, evaluate(t)))
            .Aggregate((max, next) => next.Item2.CompareTo(max.Item2) > 0 ? next : max).Item1;
    }

    public static T MinBy<T, R>(this IEnumerable<T> en, Func<T, R> evaluate) where R : IComparable<R>
    {
        return en.Select(t => new Tuple<T, R>(t, evaluate(t)))
            .Aggregate((max, next) => next.Item2.CompareTo(max.Item2) < 0 ? next : max).Item1;
    }
}

你可以试试

string pairOfGroupWithHighestProfitSum = data.GroupBy(e => e.Pair).
Select(e => new { Pair = e.Key, Count = e.Count(), ProfitSum = e.Sum(e => e.ProfitPercentage), Value = e }).
OrderByDescending(e => e.ProfitSum).
FirstOrDefault()?.Pair;

如果你的data为空,则为null,否则你将获得利润总额最高的组对。

如果您使用 .NET Core,您不会通过先排序然后取第一个值来查找最大值来获得性能损失。参见 https://docs.microsoft.com/en-us/dotnet/core/compatibility/core-libraries/5.0/orderby-firstordefault-complexity-increase