使用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?
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);