跳到我的结论:如何让编译器让我使用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?
答案 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);