我有以下列表:
public class Foo
{
public int Qty { get; set; }
public IDictionary<string, object> Dxo { get; set; }
}
我正在尝试合并具有相同字典值的记录(字典中的所有道具都相同),并对合并记录的数量求和。
我有以下查询:
var result = from f in foos.Select(x => x.Exo).Distinct()
join p2 in foos on exo equals p2.Exo into gr
select new
{
Qty = gr.Select(x => x.Qty).Sum(),
Exo = exo
};
查询的不同部分似乎不起作用。我的结果有相同数量的记录。
也许无法以这种方式比较IDictionary。预先感谢!
答案 0 :(得分:2)
您可以pass自定义IEqualityComparer:
from f in foos.Distinct(new FooEqualityComparer())
如下所示:
class FooEqualityComparer : IEqualityComparer<Foo>
{
public bool Equals(Foo one, Foo two)
{
// your implementation goes here
// where you for instance compare Exo
}
public int GetHashCode (Foo foo)
{
// your implementation goes here
}
}
答案 1 :(得分:1)
您需要的(以及现成的不可用的)是检查IDictionary<string, object>
实例是否相等的功能。
当您使用.Distinct()
时,将使用标准.Equals()
实现对这些实例进行比较,该实现只是通过引用进行比较,而不是您所需要的。
此外,由于此后您需要处理“相等”的记录,因此最好将.GroupBy()
与.Distinct()
一起使用Join
,而不是FooComparer
,因为这样更明显,性能也更高(如无论如何,我们仍然可以谈论此任务的性能)。
因此,假设我们有一些var result = foos
.GroupBy(x => x.Dxo, x => x, new FooComparer())
.Select(x => new Foo
{
Qty = x.Sum(y => y.Qty),
Dxo = x.First().Dxo,
})
.ToArray();
可以比较项目,则您的查询应类似于:
public class FooComparer : IEqualityComparer<IDictionary<string, object>>
{
public bool Equals(IDictionary<string, object> x, IDictionary<string, object> y)
{
return x.Keys.All(k => x[k] == y[k]);
}
public int GetHashCode(IDictionary<string, object> obj)
{
return obj.Aggregate(0, (hash, x) => (x.Value?.GetHashCode() ?? 0) ^ hash);
}
}
现在切换到该比较器。
我从您的疑问中读到了这句话:“字典中的所有道具都是相同的”,因为“每个字典都具有完全相同的键集,并且所有字典都不为空”。那是非常严格的语句,它简化了我们的任务,因此比较器看起来像:
x[k] == y[k]
这里有几点注意事项:
Distinct
需要进一步编码以进行比较,说到这-我将永远不会使用基于LINQ的方法来完成这项任务。我怀疑LINQ到对象的.Net Group By
/ GetEquals
的复杂度在O(n ^ 2)左右(我没有寻找内部实现,但我高度怀疑没有真正的优化可以在此处完成通用方法)。
因此,在GroupBy期间对比较器中每个该死的export class UpdateStepDetailsComponent implements AfterViewInit {
@Input() step: LogUpdateStep;
@Input() conn: HubConnection;
constructor() { }
ngAfterViewInit() {
this.conn.on("StepProgress", this.hubReturn)
}
getProgress() {
this.conn.invoke("GetProgress", this.step.idupdate, this.step.step)
}
hubReturn(text) {
console.log('return', text)
this.step.stepText = text
console.log('why is step undefined here?', this.step)
}
}
进行每个字典的枚举和随后的每个项的比较都是一个大麻烦。
我会在foreach循环中进行重做,可能会为散列/等式进行一些缓存,或者可能会更改整个方法以与开始时不同的方式解决该任务,以便从开始就将结果累积在同一对象中。 / p>
答案 2 :(得分:0)
您可以在IDictionary上创建扩展方法IsSameAs
。该方法应返回一个布尔值,指示2个字典是否相等。然后,您可以像使用LINQ
foos.Where(f1 => foos.Any(f2 => f1.exo.IsSameAs(f2.exo))).Select(....)
当然,缺点之一是它会与他人相匹配。