Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/linq/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 按IDictionary选择不同的记录<;字符串,对象>;对象中的属性_C#_Linq - Fatal编程技术网

C# 按IDictionary选择不同的记录<;字符串,对象>;对象中的属性

C# 按IDictionary选择不同的记录<;字符串,对象>;对象中的属性,c#,linq,C#,Linq,我有以下清单: public class Foo { public int Qty { get; set; } public IDictionary<string, object> Dxo { get; set; } } 我的查询的独特部分似乎不起作用。我的结果有相同数量的记录 也许以这种方式比较IDictionary是不可能的。提前谢谢 您可以在IDictionary上创建扩展方法IsSameAs。该方法应返回一个布尔值,指示两个字典是否相等。然后你就可以像这样

我有以下清单:

public class Foo
{
    public int Qty { get; set; }

    public IDictionary<string, object> Dxo { get; set; }
}
我的查询的独特部分似乎不起作用。我的结果有相同数量的记录


也许以这种方式比较IDictionary是不可能的。提前谢谢

您可以在IDictionary上创建扩展方法
IsSameAs
。该方法应返回一个布尔值,指示两个字典是否相等。然后你就可以像这样使用LINQ了

foos.Where(f1 => foos.Any(f2 => f1.exo.IsSameAs(f2.exo))).Select(....)
当然,一个缺点是它会与自我和他人匹配。

您可以自定义:

看起来是这样的:

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
    }
}
class FooEqualityComparer:IEqualityComparer
{
公共布尔等于(Foo-one,Foo-two)
{
//你的实现就在这里
//例如,您可以比较Exo
}
公共int GetHashCode(Foo-Foo)
{
//你的实现就在这里
}
}
您需要的(以及开箱即用不可用的)是检查
IDictionary
实例是否相等的功能

当您使用
.Distinct()
时,将使用标准的
.Equals()
实现来比较这些实例,这只是通过引用进行比较,而不是您需要的

此外,由于您需要在此之后处理“相等”记录,因此最好使用
.GroupBy()
而不是
.Distinct()
连接,因为这更明显,性能也更高(无论如何,我们都可以在此任务中讨论性能)

因此,假设我们有一些可以比较项目的
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);
    }
}
现在切换到比较器

我从你的问题“字典中的所有道具都是一样的”中读到了这句话,就像“每本字典都有完全相同的密钥集,并且所有字典都不是空的”。这是一条非常严格的语句,它简化了我们的任务,因此comparer可以如下所示:

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);
    }
}
公共类FooComparer:IEqualityComparer
{
公共布尔等于(IDictionary x,IDictionary y)
{
返回x.Keys.All(k=>x[k]==y[k]);
}
public int GetHashCode(IDictionary obj)
{
返回obj.Aggregate(0,(散列,x)=>(x.Value?.GetHashCode()?0)^hash);
}
}
这里有几条通知:

  • 如果字典中的值是非常复杂的对象(即int/string之类的非原始对象),那么上面的
    x[k]==y[k]
    需要进一步编码来比较它们
  • 在这里计算hashcode只是一个伪代码(但这应该是可行的);我决不会将其用于生产代码
说到这里,我永远不会使用基于LINQ的方法来完成这样的任务。我怀疑.Net
Distinct
/
Group By
的复杂性对于LINQ to对象来说大约是O(n^2)(我还没有寻找内部实现,但我高度怀疑对于通用方法来说并没有真正的优化)

因此,在GroupBy期间,在comparer中为每个该死的
GetEquals
,枚举每一个字典,并对其中的每一项进行后续比较,这是一个巨大的失败


我会在foreach循环中对其进行修改,可能会对hash/equals进行一些缓存,或者可能会改变整个方法,从一开始就以不同的方式解决该任务,以便从一开始就在同一对象中累积结果。

您没有任何方法将一个字典与另一个字典进行比较,并且字典类中也没有标准的比较方法。
on exo等于p2。exo
← 那不行。联接可以比较基元类型(如字符串、int等),也可以使用匿名类型,其中属性是具有相同属性名称的基元类型(示例
on new{Name=“dave”}等于new{Name=o.Name}
。Dictionary是一种复杂的类型,因此如果您想在Dictionary上执行联接,您需要编写一些比较运算符或实现一个可以执行此操作的接口,但我不认为您可以在联接中执行此操作。我建议您使用一些
foreach
循环写出您试图执行的操作,并将其实际用于ork(不是伪代码)。那么你将有更好的机会将其转换为linq。你可以创建一个完整的,并将其添加到你的问题中。非常感谢你的非常详细的回答。我将把它投入到生产中。顺便说一句,由于我正在尝试查找类似IDictionary的对象(而且很匆忙),我只是“扁平的"将整个对象转换为json字符串,然后比较字符串。现在完成了这项工作。再次感谢!!感谢您的回复。我非常感激。所有的答案几乎都建议使用相同的方法,但我将其授予@Lanorkin,因为他回复的详细程度。@juliandromon:他发布的答案比我晚,所以我没有看到它。公平地说,他值得接受。谢谢!谢谢你的回复。我非常感谢。所有的答案几乎都表明了相同的方法,但我把它授予@Lanorkin,因为他回复中的详细程度。