如何比较包含包含字典的对象的两个列表?

时间:2014-01-06 12:30:10

标签: c# list

我有两个列表(列出“A”和列表“B”),它们包含“KeyStore”类型的对象,如下所示:

public class KeyStore
{
    public Dictionary<string, string> PrimaryKeys { get; set; }

    public KeyStore(string pkName, string pkValue)
    {
        PrimaryKeys = new Dictionary<string, string> {{pkName, pkValue}};
    }

    public KeyStore()
    {
        PrimaryKeys = new Dictionary<string, string>();
    }
}

我需要查看列表“A”中的每条记录,看看列表“B”中是否有匹配的记录。如果有,则该记录需要存储在仅包含匹配记录的新列表中。如果记录的PrimaryKeys字典包含与列表“B”中的记录相同的条目数和相同的键值组合,则认为匹配为真。在测试相等性时,字典中条目的顺序并不重要。如果列表“A”中的记录在列表“B”中没有匹配,则需要将其存储在新列表中,该列表仅包含在列表“A”中找到的记录。

之前我做了类似的事情,当我有字符串列表时,我使用“Intersect”和“Except”来创建匹配和不匹配记录的列表。我现在假设我需要比较这些KeyStore对象,我需要提高一定程度的复杂性。任何人都可以提供解决方案或建议如何解决这个问题吗?

编辑1 ----------------

根据评论,我创建了一个实现IEqualityComparer的类,如下所示:

class KeyStoreComparer : IEqualityComparer<KeyStore>
{
    public bool Equals(KeyStore x, KeyStore y)
    {
        if (x != null && x.PrimaryKeys.Count == y.PrimaryKeys.Count)
        {
            return x.PrimaryKeys.Keys.All(k => y.PrimaryKeys.ContainsKey(k)) &&
                   x.PrimaryKeys.Keys.All(k => x.PrimaryKeys[k].Equals(y.PrimaryKeys[k]));
        }
        return false;
    }

    public int GetHashCode(KeyStore obj)
    {
        return ReferenceEquals(obj, null) ? 0 : obj.GetHashCode();
    }
}

我创建了一些虚拟数据但是当运行“Intersect”命令时,从不调用上面的代码。我出错的任何想法?

var ListA = new List<KeyStore>();
ListA.Add(new KeyStore("a", "b"));
ListA.Add(new KeyStore("c", "d"));

var ListB = new List<KeyStore>();
ListB.Add(new KeyStore("a", "b"));
ListB.Add(new KeyStore("x", "y"));

var g = ListA.Intersect(ListB, new KeyStoreComparer());

“Equals”和“GetHashCode”中的代码可能不正确,但我只是试图让它在运行之前得到它。

编辑2 ---------------------------------------

我对KeyStore类进行了各种更改,如本页“fox”中的示例所示。我仍然没有得到被调用的重写函数。作为一项实验,我尝试了这个:

var result = ListA.Equals(ListB);

当我这样做时,KeyStor类中被覆盖的函数不会运行。但如果我这样做:

var result = ListA[0].Equals(ListB[0]);

重写的函数会运行并提供预期的结果。任何人都知道如何让这个对列表中的所有项目起作用而不仅仅是针对单个记录?

编辑3 ---------------------------------------

我看到的问题是覆盖适用于单个项目,例如:

var a = new KeyStore("a", "b");
var b = new KeyStore("a", "b");
var c = a.Equals(b);

当我在KeyStore上运行上面的断点时,“Equals”功能被击中。一旦我尝试使用List of KeyStore做类似的事情,断点就不再被击中了。使用列表时,我是否需要做一些额外的事情?

2 个答案:

答案 0 :(得分:0)

public class KeyStore
{
    public Dictionary<string, string> PrimaryKeys { get; set; }

    public KeyStore(string pkName, string pkValue)
    {
        PrimaryKeys = new Dictionary<string, string> { { pkName, pkValue } };
    }

    public KeyStore()
    {
        PrimaryKeys = new Dictionary<string, string>();
    }

    public override bool Equals(object obj)
    {
        // If parameter is null return false.
        if (obj == null)
            return false;

        // If parameter cannot be cast to KeyStore return false.
        KeyStore targetKeyStore = obj as KeyStore;
        if (targetKeyStore == null)
            return false;

        return PrimaryKeys.OrderBy(pk => pk.Key).SequenceEqual(targetKeyStore.PrimaryKeys.OrderBy(pk => pk.Key));
    }

    public override int GetHashCode()
    {
        StringBuilder content = new StringBuilder();

        foreach (var item in PrimaryKeys.OrderBy(pk => pk.Key))
            content.AppendFormat("{0}-{1}", item.Key, item.Value);

        return content.ToString().GetHashCode();
    }
}

Eric Lippert's guide on implementing GetHashCode写道,“相等的项目具有相同的哈希值”。上面的GetHashCode()实现只是为了显示概念,可能不适合生产代码。

答案 1 :(得分:0)

重写ToString方法将有助于简化代码。看看这是否有帮助:

public class KeyStore
{
    public SortedDictionary<string, string> PrimaryKeys
    {
        get;
        set;
    }

    public KeyStore(string pkName, string pkValue)
    {
        PrimaryKeys = new SortedDictionary<string, string> { { pkName, pkValue } };
    }

    public KeyStore()
    {
        PrimaryKeys = new SortedDictionary<string, string>();
    }

    public override bool Equals(object obj)
    {
        if(obj == null || (KeyStore)obj == null)
            return false;
        KeyStore temp = (KeyStore)obj;

        return ToString() == temp.ToString();
    }

    public override int GetHashCode()
    {
        return ToString().GetHashCode();
    }
    public override string ToString()
    {
        return PrimaryKeys.Count.ToString() + " : \n" + string.Join("\n",(from kvp in PrimaryKeys
                                                                          let s = kvp.Key + " - " + kvp.Value
                                                                          select s));
    }
}

List<KeyStore> Lista = new List<KeyStore>
{
    new KeyStore("testa","testa1"),
    new KeyStore("testb","testb1"),
    new KeyStore("testc", "testc1")
};
List<KeyStore> Listb = new List<KeyStore>
{
    new KeyStore("testa","testa1"),
    new KeyStore("testd","testb1"),
    new KeyStore("testc", "testa1"),
    new KeyStore("teste", "teste1")
};
var Listc = Lista.Intersect(Listb).ToList();
var Listd = Lista.Except(Listb).ToList();

?Listc
Count = 1
    [0]: {1 : 
testa - testa1}

?Listd
Count = 2
    [0]: {1 : 
testb - testb1}
    [1]: {1 : 
testc - testc1}