Реализуйте пользовательский хэш-код в стороннем классе - PullRequest
0 голосов
/ 11 октября 2019

Я использую класс Line в проекте VisualStudio C # от третьей стороны (нет доступа к источнику). Мой код генерирует сотни / тысячи строковых объектов, содержащих дубликаты, и мне нужно хранить их в какой-либо коллекции (СписокHashSet) для дальнейшей обработки (рисование на экране). Класс Line имеет свойства StartPoint и EndPoint типа Point и других. Для целей, которые мне нужны, ориентация линии не имеет значения, и если начальная и конечная точки одинаковы, два объекта Line одинаковы. Класс, который я использую, ведет себя по-разному, и два объекта Line считаются уникальными, даже если они имеют одинаковые начальные / конечные точки. (GetHashCode возвращает разные значения) Вопрос в том, как реализовать пользовательские процедуры IComparer или GetHashCode для стороннего класса, чтобы иметь возможность использовать структуру HashSet или функцию List.Distinct ()?

СпасибоИлиан и Хасан, которые сделали трюк Быстрый ответ на вопрос, если вы не возражаете: я не был уверен, использовать ли List или HashSet для хранения моих данных, поэтому я попробовал и рассчитал оба. Результаты показывают, что один на несколько порядков медленнее другого. Любое понимание того, что происходит?

class LineComparer : IEqualityComparer<Line>
{
    public bool Equals(Line l1, Line l2)
    {
        if (l1.EndPoint == l2.EndPoint && l1.StartPoint == l2.StartPoint) return true;
        if (l1.EndPoint == l2.StartPoint && l1.StartPoint == l2.EndPoint) return true;
        return false;
    }
    public int GetHashCode(Line line) => line.StartPoint.GetHashCode() ^ line.EndPoint.GetHashCode();
}

, и это мой код для HashSet:

var timer = new Stopwatch();

timer.Start ();

var result =new HashSet (new LineComparer ());

GenerateAndStore20000Lines ();

timer.Stop ();Ed.WriteMessage ($ "\ nGenerated {result.Count} строк, время с хэш-набором: {timer.ElapsedMilliseconds}");

возврат результата;

Results: * Время с HashSet: 1302* Время с HashSet: 1328 * Время с HashSet: 1314 * Время с HashSet: 1311 * Время с HashSet: 1303

Код с List:

var timer = new Stopwatch ();timer.Start ();

var result = new List ();

GenerateAndStore20000Lines ();

timer.Stop ();Ed.WriteMessage ($ "\ nGenerated {result.Count} строк, время со списком: {timer.ElapsedMilliseconds}");

возвращать result.Distinct (new LineComparer ());

Результаты:

  • Сгенерировано 20002 строки, время со списком: 26
  • Сгенерировано 20002 строки, время со списком: 11
  • Сгенерировано 20002 строки, время со списком: 14
  • Сгенерировано 20002 строки, время со списком: 12
  • Сгенерировано 20002 строки, время со списком: 12

(извините за плохое форматирование, но этот интерфейссводит меня с ума ... сдаюсь)

Ответы [ 2 ]

0 голосов
/ 11 октября 2019

Я только расширяю ответ @ Ilian . Попытался прокомментировать как можно больше, поэтому я считаю, что для кода лучше говорить:)

// Mock 3rd Party point
public class ThirdPartyPoint {

}

// Mock 3rd party line
public class ThirdPartyLine {

    public ThirdPartyPoint StartPoint { get; set; }
    public ThirdPartyPoint EndPoint { get; set; }

}

// This class implements IEqualityComparer<ThirdPartyLine>, which compares
// ThirdPartyLine's equality. THis class will be passed as a ctor arument to HashSet<T>
public class CompareLines : IEqualityComparer<ThirdPartyLine> {

    public bool Equals(ThirdPartyLine x, ThirdPartyLine y) {
        // Here check for the equality of the start and end points.
        // I asuumed the following but do not know how the eaulity is implemented in your library.
        return x.EndPoint == y.EndPoint && x.StartPoint == y.StartPoint;
    }

    public int GetHashCode(ThirdPartyLine obj) {
        // Implement an algortihm which must return same hashcode for objects considered the same.
        // I am not sure about the Point class hashcode but I am jsut assuming the following.
        return obj.StartPoint.GetHashCode() ^ obj.EndPoint.GetHashCode();
    }

}


private static void Main(string[] args) {
    // Hashset to hold lines
    var hashSet = new HashSet<ThirdPartyLine>(new Compare());
    // start point
    var starPoint = new ThirdPartyPoint();
    // end point
    var endPoint = new ThirdPartyPoint();

    // Lines with same start and end points
    var line1 = new ThirdPartyLine {
        StartPoint = starPoint,
        EndPoint = endPoint
    };

    var line2 = new ThirdPartyLine {
        StartPoint = starPoint,
        EndPoint = endPoint
    };


    // Check count first
    hashSet.Add(line1);
    var count = hashSet.Count;

    // Check count second, still 1
    hashSet.Add(line2);
    count = hashSet.Count;
}
0 голосов
/ 11 октября 2019

Используйте перегрузки с IEqualityComparer (что вам придется реализовать).

См. это для HashSet.

Я полагаю, вы имеете в виду Enumerable.Distinct. Используйте this .

...