如何按值比较两个词典,即使键或值是引用类型?

时间:2018-02-20 10:05:15

标签: c# list dictionary equals

我想比较两个Dictionary<SomeClass, List<AnotherClass>>。无论KeyValuePair的顺序如何,都应该比较字典。在评论中,建议对值进行排序,然后使用SequenceEquals,但我不确定如何Sort字典(甚至,即使对lists进行排序也有帮助,这是不可能的据我所知,因为列表的泛型类型不能保证为IComparable)。

当我尝试使用Equals方法时,我总是得到false,因为它会检查List是否为引用等号。我希望它检查List s是否等于值。怎么做到这一点?

例如,假设我有以下词典:

var dictionary1 = new Dictionary<Day, List<WorkSession>>
{
    { Day.Tuesday, new List<WorkSession>() { new WorkSession("22:00", "00:00") } },
    { Day.Monday, new List<WorkSession>() { new WorkSession("20:00", "00:00") } },
    { Day.Sunday, new List<WorkSession>() { new WorkSession("10:00", "00:00") } }
};

var dictionary2 = new Dictionary<Day, List<WorkSession>>
{
    { Day.Sunday, new List<WorkSession>() { new WorkSession("10:00", "00:00") } },
    { Day.Monday, new List<WorkSession>() { new WorkSession("20:00", "00:00") } },
    { Day.Tuesday, new List<WorkSession>() { new WorkSession("22:00", "00:00") } }
};

分工作业:

class WorkSession : IEquatable<WorkSession>
{
    public string Entrance { get; private set; }
    public string Exit { get; private set; }

    public WorkSession(string entrance, string exit)
    {
        Entrance = entrance;
        Exit = exit;
    }

    public override bool Equals(object obj)
    {
        return Equals(obj as WorkSession);
    }
    public bool Equals(WorkSession other)
    {
        return other != null &&
               Entrance == other.Entrance &&
               Exit == other.Exit;
    }
    public override int GetHashCode()
    {
        var hashCode = 1257807568;
        hashCode = hashCode * -1521134295 + EqualityComparer<string>.Default.GetHashCode(Entrance);
        hashCode = hashCode * -1521134295 + EqualityComparer<string>.Default.GetHashCode(Exit);
        return hashCode;
    }

    public static bool operator ==(WorkSession session1, WorkSession session2)
    {
        return EqualityComparer<WorkSession>.Default.Equals(session1, session2);
    }
    public static bool operator !=(WorkSession session1, WorkSession session2)
    {
        return !(session1 == session2);
    }
}

我希望两个比较这些词典,结果应该是True。我怎么能做到这一点?

2 个答案:

答案 0 :(得分:1)

这是一些可以帮助你入门的原油。您需要考虑一些边缘情况并相应地调整代码。

 JsonArray convertListToJSOnBox(ArrayList<CartItemBean> list) {

    JsonArray result = (JsonArray) new Gson().toJsonTree(list,
            new TypeToken<List<CartItemBean>>() {
            }.getType());


    return result;
}

答案 1 :(得分:1)

可能的解决方案如下。与其他一些答案相比,平等检查略有收紧。例如,添加了一些null检查,并以不同的方式检查值(基本上不仅检查Values是否相同,而且对于给定的密钥,它们是相同的 < /强>)。

此外,在比较列表时,数据按WorkSession的所有属性排序 - 以防两个不同的WorkSession值具有相同的哈希码。 更好的长期解决方案是WorkSession实施IComparable

using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;

namespace MattConsole
{
    class Program
    {
        static void Main(string[] args)
        {
            var x = new Dictionary<Day, List<WorkSession>>
            {
                { Day.Tuesday, new List<WorkSession>() { new WorkSession("22:00", "00:00") } },
                { Day.Monday, new List<WorkSession>() { new WorkSession("20:00", "00:00") } },
                { Day.Sunday, new List<WorkSession>() { new WorkSession("10:00", "00:00") } }
            };

            var y = new Dictionary<Day, List<WorkSession>>
            {
                { Day.Sunday, new List<WorkSession>() { new WorkSession("10:00", "00:00") } },
                { Day.Monday, new List<WorkSession>() { new WorkSession("20:00", "00:00") } },
                { Day.Tuesday, new List<WorkSession>() { new WorkSession("22:00", "00:00") } }
            };
            var w = new MyCustomComparer();
            var shouldBeTrue = w.Equals(x, y);

            Console.WriteLine(shouldBeTrue);

            x[Day.Wednesday] = new List<WorkSession>() { new WorkSession("10:00", "00:00") };
            x[Day.Thursday] = new List<WorkSession>() { new WorkSession("10:01", "00:01") };
            y[Day.Thursday] = new List<WorkSession>() { new WorkSession("10:00", "00:00") };
            y[Day.Wednesday] = new List<WorkSession>() { new WorkSession("10:01", "00:01") };

            var shouldBeFalse = w.Equals(x, y);

            Console.WriteLine(shouldBeFalse);

            Console.ReadLine();
        }
    }

    public class MyCustomComparer : IEqualityComparer<Dictionary<Day, List<WorkSession>>>
    {
        public bool Equals(Dictionary<Day, List<WorkSession>> x, Dictionary<Day, List<WorkSession>> y)
        {
            if (ReferenceEquals(x, null))
                return ReferenceEquals(y, null);

            if (ReferenceEquals(y, null))
                return false;

            if (x.Count != y.Count)
                return false;

            if (!x.Keys.OrderBy(z => z).SequenceEqual(y.Keys.OrderBy(z => z)))
                return false;

            foreach (var kvp in x)
            {
                List<WorkSession> matching;
                if (y.TryGetValue(kvp.Key, out matching))
                {
                    if (ReferenceEquals(matching, null))
                        return ReferenceEquals(kvp.Value, null);

                    if (ReferenceEquals(kvp.Value, null))
                        return false;

                    // ordering by hash code is not strictly necessary
                    if (
                        !matching.OrderBy(z => z.GetHashCode())
                            .ThenBy(z => z.Entrance).ThenBy(z => z.Exit)
                            .SequenceEqual(
                                kvp.Value.OrderBy(z => z.GetHashCode())
                                .ThenBy(z => z.Entrance).ThenBy(z => z.Exit)))
                        return false;
                }
                else
                    return false;
            }

            return true;
        }

        public int GetHashCode(Dictionary<Day, List<WorkSession>> obj)
        {
            throw new NotImplementedException();
        }
    }

    public class WorkSession : IEquatable<WorkSession>
    {
        public string Entrance { get; private set; }
        public string Exit { get; private set; }

        public WorkSession(string entrance, string exit)
        {
            Entrance = entrance;
            Exit = exit;
        }

        public override bool Equals(object obj)
        {
            return Equals(obj as WorkSession);
        }
        public bool Equals(WorkSession other)
        {
            return other != null &&
                   Entrance == other.Entrance &&
                   Exit == other.Exit;
        }
        public override int GetHashCode()
        {
            var hashCode = 1257807568;
            hashCode = hashCode * -1521134295 + EqualityComparer<string>.Default.GetHashCode(Entrance);
            hashCode = hashCode * -1521134295 + EqualityComparer<string>.Default.GetHashCode(Exit);
            return hashCode;
        }

        public static bool operator ==(WorkSession session1, WorkSession session2)
        {
            return EqualityComparer<WorkSession>.Default.Equals(session1, session2);
        }
        public static bool operator !=(WorkSession session1, WorkSession session2)
        {
            return !(session1 == session2);
        }
    }
}