linq Кроме и пользовательский IEqualityComparer

Я пытаюсь реализовать пользовательский компаратор в двух списках строк и использовать.Except () linq метод для получения тех, которые не являются одним из списков. Причина я делаю пользовательский компаратор, состоит в том, потому что я должен сделать, "нечеткое" выдерживает сравнение, т.е. одна строка в одном списке могла быть встроена в строке в другом списке.

Я сделал следующий компаратор

public class ItemFuzzyMatchComparer : IEqualityComparer<string>
{
    bool IEqualityComparer<string>.Equals(string x, string y)
    {
        return (x.Contains(y) || y.Contains(x));
    }

    int IEqualityComparer<string>.GetHashCode(string obj)
    {
        if (Object.ReferenceEquals(obj, null))
            return 0;
        return obj.GetHashCode();
    }
}

Когда я отлаживаю, единственная точка останова, которая хиты находится в GetHashCode () метод. Равняние () никогда не затрагивается. Какие-либо идеи?

19
задан Reed Copsey 23 March 2010 в 15:16
поделиться

3 ответа

Если все возвращенные хэш-коды различны, сравнивать на равенство не нужно.

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

Вы должны убедиться, что если Equals (a, b) возвращает истину, то GetHashCode (a) == GetHashCode (b) . (Обратное не обязательно - конфликты хэшей допустимы, хотя, очевидно, вы хотите, чтобы их было как можно меньше.)

18
ответ дан 30 November 2019 в 04:29
поделиться

Как указал Джон, вам нужно убедиться, что хэш-код двух строк равен (согласно вашему правилу сравнения). К сожалению, это довольно сложно.

Чтобы продемонстрировать проблему, Equals (str, "") возвращает истину для всех строк str , что по сути означает, что все строки равны пустой строке и, как результат , все строки должны иметь тот же хэш-код, что и пустая строка.Следовательно, единственный способ правильно реализовать IEqualityComparer - всегда возвращать один и тот же хэш-код:

public class ItemFuzzyMatchComparer : IEqualityComparer<string>  { 
  bool IEqualityComparer<string>.Equals(string x, string y)  { 
    return (x.Contains(y) || y.Contains(x)); 
  }  
  int IEqualityComparer<string>.GetHashCode(string obj)  { 
    if (Object.ReferenceEquals(obj, null)) return 0; 
    return 1; 
  } 
}

Затем вы можете использовать метод Except , и он будет вести себя правильно. Единственная проблема в том, что вы (вероятно) получите довольно неэффективную реализацию, поэтому, если вам нужна более высокая производительность, вам, возможно, придется реализовать свою собственную кроме . Однако я не совсем уверен, насколько неэффективной будет реализация LINQ, и я не уверен, действительно ли возможно иметь какую-либо эффективную реализацию для вашего правила сравнения.

6
ответ дан 30 November 2019 в 04:29
поделиться

Возможно, эту проблему можно было бы решить без реализации интерфейса IEqualityComparer. У Джона и Томаса есть хорошие моменты в реализации этого интерфейса, и равенство, похоже, не определяет вашу проблему. Судя по вашему описанию, я думаю, вы могли бы сделать это без использования расширения Except во время сравнения. Вместо этого сначала найдите совпадения, а затем выполните Except. Посмотрите, поможет ли это вам:

 List<String> listOne = new List<string>(){"hard", "fun", "code", "rocks"};
 List<String> listTwo = new List<string>(){"fund", "ode", "ard"};

 var fuzzyMatchList = from str in listOne
                      from sr2 in listTwo
                      where str.Contains(sr2) || sr2.Contains(str)
                      select str;
 var exceptList = listOne.Except(fuzzyMatchList);
1
ответ дан 30 November 2019 в 04:29
поделиться
Другие вопросы по тегам:

Похожие вопросы: