Как я могу использовать HashSet <MyCustomClass>для удаления дубликатов MyCustomClass? - PullRequest
4 голосов
/ 20 июня 2010

У меня есть HashSet<MyCustomClass> mySet = new HashSet<MyCustomClass>();, и я хочу удалить все MyCustomClass, которые содержат одинаковые значения.

Допустим, MyCustomClass выглядит следующим образом:

public class MyCustomClass
{
    Point point;

    public MyCustomClass(int x, int y)
    {
        point.X = x;
        point.Y = y;
    }

    // Other methods...
}

Я попытался реализовать IEqualityComparer, как предлагает MSDN, и пропустить его через конструктор HashSet<MyCustomClass>();, но в итоге я не смог.

Какой правильный подход?

РЕДАКТИРОВАТЬ:

Это мой Chain класс и мой ChainEqualityComparer:

public class Chain
{
    HashSet<Mark> chain;
    HashSet<Mark> marks;

    public Chain(HashSet<Mark> marks)
    {
        chain = new HashSet<Mark>();
        this.marks = marks;
    }       
    // Other methods...
}

public class ChainEqualityComparer : IEqualityComparer<Chain>
{
    #region IEqualityComparer<Chain> Members

    public bool Equals(Chain x, Chain y)
    {
        if (x.ChainWithMarks.Count == y.ChainWithMarks.Count)
        {
            foreach (Mark mark in x.ChainWithMarks)
            {
                if (!y.ChainWithMarks.Contains(mark))
                    return false;
            }
            return true;
        }

        return false;
    }

    public int GetHashCode(Chain obj)
    {
        return obj.GetHashCode() ^ obj.GetType().GetHashCode();
    }

    #endregion
}

А это мой Mark класс:

  public class Mark
{
    int x;
    int y;

    public Mark(int x, int y)
    {
        this.x = x;
        this.y = y;
    }

    public int X
    {
        get { return x; }
        set { x = value; }
    }

    public int Y
    {
        get { return y; }
        set { y = value; }
    }
}

public class MarkEqualityComparer : IEqualityComparer<Mark>
{
    #region IEqualityComparer<Mark> Members

    public bool Equals(Mark x, Mark y)
    {
        return (x.X == y.X) && (x.Y == y.Y);
    }

    public int GetHashCode(Mark obj)
    {
        return obj.GetHashCode() ^ obj.GetType().GetHashCode();
    }

    #endregion
}

(я могу вставить код, если его слишком много ...)

Ответы [ 2 ]

5 голосов
/ 20 июня 2010

Вы можете использовать EqualityComparer или просто переопределить Equals и GetHashCode.

Вы должны убедиться, что все, что вы считаете дубликатом , идентифицируется как имеющее эквивалентный хеш-код, и возвращает значение true при проверке на равенство.

Я предполагаю, что вы не возвращали одинаковые хэш-коды. Не могли бы вы опубликовать код из вашего сравнения равенства?

В качестве теста вы можете сделать:

var set = new HashSet<MyCustomClass>();
var a = new MyCustomClass(1,2);
var b = new MyCustomClass(1,2);
set.Add(a);
set.Add(b);
Assert.IsTrue(a.Equals(b));
Assert.IsTrue(b.Equals(a));
Assert.AreEqual(a.GetHashCode(), b.GetHashCode());
Assert.AreEqual(1, set.Count);

Аналогичный набор тестов применим и к средству сравнения на равенство.

EDIT

Да, как и предполагалось, это функция хеш-кода. Вы должны рассчитать его на основе значений самого типа. Довольно распространенная ошибка.

public int GetHashCode(Mark obj)
{
    return ((MyCustomClass)obj).point.GetHashCode();
}

Предполагается, что point является единственным полем состояния в вашем типе.

2 голосов
/ 20 июня 2010

Я думаю, что вас запутали, потому что два Mark экземпляра с одинаковыми значениями не будут равны в вашем ChainEqualityComparer классе.Не похоже, что MarkEqualityComparer используется когда-либо.

Строка:

if (!y.ChainWithMarks.Contains(mark))

всегда будет ложной, если вы не переопределите Equals и GetHashCode для Markучебный класс.(За исключением случаев, когда у вас есть две ссылки на одну и ту же метку в цепочке x и цепочке y, что, я полагаю, не то, что вам нужно).

Если y.ChainWithMarks является HashSet и вы хотите использовать MarkEqualityComparer, убедитесь, что вы создали этот HashSet с правильным конструктором, включая экземпляр MarkEqualityComparer.

Поскольку Mark является типом значения, вы можете рассмотреть возможность использования структуры для его представления, поскольку среда выполнения .Net тогда использует равенство значений вместо ссылочного равенства при сравнении.Я думаю, что это на самом деле самая правильная реализация вашей идеи.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...