使用Linq对数据集进行分区

时间:2014-08-05 02:49:37

标签: c# linq compiler-errors type-inference

跳到我的结论:如何让编译器让我使用GroupJoin?

我有成员Double [] rawData,我找到minValue和maxValue。我想对这些数据进行分区,以便制作条形图。我的最终结果将是一个OrderedDictionary,其中Key是条形图每个条形的中心值,int是条形范围内的项目数。

我可以使用foreaches等自己编写这个,但我想利用这些经验来学习更多关于Linq的知识。我很确定我应该使用GroupJoin。 (如果错误,请纠正我。)

使用minVal,maxVal和numberOfBars,我创建了一个列表栏,其中xRange代表条形图中的单个栏。

我遇到了一定的编译错误,我无法弄清楚如何通过它:

方法' System.Linq.Enumerable.GroupJoin的类型参数(System.Collections.Generic.IEnumerable,System.Collections.Generic.IEnumerable,System.Func,System.Func,System.Func,TResult> )'无法从使用中推断出来。尝试明确指定类型参数。

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

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

(稍后我将把它写入字典,只需要使用samplePoints.Count。)

我也尝试过传递lambda for comparer的重载:

最后,作为背景,这里是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?

2 个答案:

答案 0 :(得分:1)

联接只能在您加入相同类型的键时才能工作。

这是您尝试使用的签名:

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(),
    };

答案 1 :(得分:0)

GroupJoin仅支持 equi 加入 - 内键和外键类型必须相同。在您的示例中,outerKeySelector是xRange,innerKeySelector是双倍。

根据您的要求,我认为这样的事情可能会这样:

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);  
相关问题