使用Linq对数据集进行分区

本文关键字:分区 数据集 Linq 使用 | 更新日期: 2023-09-27 18:16:18

跳到我的结论:我该怎么做才能使编译器允许我使用GroupJoin?

我有成员Double[] rawData,我找到minValue和maxValue。我想把这些数据划分成条形图。我的最终结果将是一个OrderedDictionary,其中Key是柱状图中每个柱状图的中心值,int是位于柱状图范围内的项数。

我可以自己用foreaches之类的东西来写这个,但是我想用这个经验来学习更多关于Linq的知识。我很确定我应该使用GroupJoin。(如有错误请指正)

使用minVal, maxVal和numberOfBars,我已经组成了一个列表栏,其中xRange表示条形图中的单个条形。

我得到一个特定的编译错误,我只是不知道如何通过它:

方法"System.Linq.Enumerable.GroupJoin(System.Collections.Generic. generic)"的类型参数。IEnumerable, System.Collections.Generic。IEnumerable,系统。函数,系统。Func, System.Func, result>)'不能从用法中推断出来。尝试显式指定类型参数。

基于此,这是我的方法调用(不编译):

var result = bars.GroupJoin(
            inner: this.rawData,
            outerKeySelector: bar => bar,
            innerKeySelector: samplePoint => samplePoint,
            resultSelector: (bar, samplePoints) => samplePoints
            );

(稍后我将把它组合到字典中,只取samplePoints.Count.)

我也尝试过重载,我传递一个lambda用于比较器:

最后,作为背景,下面是xRange类:
internal class xRange : IEqualityComparer
{
    public xRange(Double low, Double high)
    {
        lowSide = low;
        highSide = high;
    }
    public Double lowSide { get; set; }
    public Double highSide { get; set; }
    public bool FallsWithin(Double val)
    { return ((val >= this.lowSide) && (val <= this.highSide));  }
    public int Compare(object x, object y)
    {
        xRange range = (xRange)x;
        Double val = (Double)y;
        if (val < range.lowSide) return -1;
        if (val > range.highSide) return 1;
        return 0;
    }
}

对以上任何一点的建议都是受欢迎的(使用GroupJoin,实现IComparer的正确方法等),但我的主要问题是,我该怎么做才能使编译器允许我使用GroupJoin?

使用Linq对数据集进行分区

join只能在相同类型的键上进行连接。

这是你想要使用的签名:

IEnumerable<TResult> GroupJoin<TOuter, TInner, TKey, TResult>(
    this IEnumerable<TOuter> outer,
    IEnumerable<TInner> inner,
    Func<TOuter, TKey> outerKeySelector,
    Func<TInner, TKey> innerKeySelector,
    Func<TOuter, IEnumerable<TInner>, TResult> resultSelector,
    IEqualityComparer<TKey> comparer
)

请注意,您需要提供IEqualityComparer<TKey>的实例,而不是IEqualityComparer,并且两个键必须为TKey类型。

要得到你想要的,试试这个查询:

var query =
    from b in bars
    select new
    {
        bar = b,
        count =
            rawData
                .Where(rd => b.FallsWithin(rd))
                .Count(),
    };

GroupJoin只支持equi连接—内外键类型必须相同。在您的示例中,outerKeySelector是xRange, innerKeySelector是double类型。

根据你的要求,我认为像这样的可以。

var groups = from bar in bars
             from datum in rawData
             where bar.FallsWithin(datum)
             group datum by bar into g
             select new
             { 
                 Mid = (bar.lowSide  + bar.highSide) / 2,
                 Count = g.Count()
             };
// Write a similar extension of SortedDictionary / SortedList if needed.
// Note: this will blow up if two bars have the same Mid.
// Note 2: A dictionary with a double as the key isn't the best idea.
var result = groups.ToDictionary(a => a.Mid, a => a.Count);