如何使用LINQ

时间:2018-06-08 16:01:40

标签: c# linq

我有问题分组对象使用linq想知道是否有人可以告诉我我在这里做错了什么。此外,select函数是我从这里抓取的扩展(the link)所以我可以主持前一个和当前值,如果值在一个范围之间,那么我将值设置为当前值。

// Range of values, the first item in the group data, i 
var ranges = new List<double> { 7.0, 6.0, 5.0, 4.0, 3.0, 2.0, 1.0 };

        // Simple class i created
        public class CurrencyGroupItemData
        {
            public string Code { get; set; }

            public double TotalStrength { get; set; }
        }

        var lstCurrencyGroups = new List<CurrencyGroupItemData>();

        lstCurrencyGroups.Add(new CurrencyGroupItemData
        { Code = "USD", TotalStrength = 5.0 });
        lstCurrencyGroups.Add(new CurrencyGroupItemData
        { Code = "CHF",TotalStrength = 2.14285714285714 });
        lstCurrencyGroups.Add(new CurrencyGroupItemData
        { Code = "EUR",TotalStrength = 3.85714285714286 });
        lstCurrencyGroups.Add(new CurrencyGroupItemData
        { Code = "GBP",TotalStrength = 3.42857142857143 });
        lstCurrencyGroups.Add(new CurrencyGroupItemData
        { Code = "JPY",TotalStrength = 5.71428571428571 });
        lstCurrencyGroups.Add(new CurrencyGroupItemData
        { Code = "CAD",TotalStrength = 6.85714285714286 });
        lstCurrencyGroups.Add(new CurrencyGroupItemData
        { Code = "AUD",TotalStrength = 4.28571428571429 });
        lstCurrencyGroups.Add(new CurrencyGroupItemData
        { Code = "NZD",TotalStrength = 4.71428571428571 });

// compare The total strength of each object, if it's value is between any of ranges above then group item by the range value. for example if the object totalstrength value is 5.7 that value is between 6.0 and 5.0, it's range value would the minimum of the 2 which 5.0, i would group that item by 5.0. 
var jjjj01 = lstCurrencyGroups.GroupBy(x => ranges.SelectWithPrev((double r1, double r2, bool isfirst)
            => (isfirst && x.TotalStrength >= r1) ? r1 : (x.TotalStrength <= r1 && x.TotalStrength <= r2) ? r2 : 0.0).ToArray())
            .Select(g => new { Rank = g.Key, Count = g.Count() })
            .ToList();

// the extension i grabbed from the link above
public static IEnumerable<TResult> SelectWithPrev<TSource, TResult>
(this IEnumerable<TSource> source, Func<TSource, TSource, bool, TResult> projection)
{
    using (var iterator = source.GetEnumerator())
    {
        var isfirst = true;
        var previous = default(TSource);
        while (iterator.MoveNext())
        {
            yield return projection(iterator.Current, previous, isfirst);
            isfirst = false;
            previous = iterator.Current;
        }
    }
}

1 个答案:

答案 0 :(得分:0)

使用我自己的扩展程序配对范围:

public static IEnumerable<TResult> ScanByPairs<T, TResult>(this IEnumerable<T> src, Func<T, T, TResult> combineFn) {
    using (var srce = src.GetEnumerator()) {
        if (srce.MoveNext()) {
            var prev = srce.Current;

            while (srce.MoveNext()) {
                yield return combineFn(prev, srce.Current);
                prev = srce.Current;
            }
        }
    }
}

答案很简单。将范围转换为范围对:

var rangesWithKey = ranges.ScanByPairs((p,c) => (max: p, min: c)).ToList();

然后按第一对包含TotalStrength

进行分组
var ans = lstCurrencyGroups.GroupBy(cg => rangesWithKey.FirstOrDefault(rk => rk.min <= cg.TotalStrength && cg.TotalStrength <= rk.max).min)
                           .Select(cgg => new { Rank = cgg.Key, Count = cgg.Count() })
                           .OrderBy(cgg => cgg.Rank);