Как перебрать только отдельные строковые значения по равенству пользовательских подстрок - PullRequest
2 голосов
/ 12 марта 2020

Подобно этому вопросу, я пытаюсь перебрать только отдельные значения подстроки заданных строк, например:

List<string> keys = new List<string>()
{
    "foo_boo_1",
    "foo_boo_2,
    "foo_boo_3,
    "boo_boo_1"
}

Вывод для выбранных отдельных значений должно быть (выбрать произвольное значение, отличное от первой подстроки):

foo_boo_1 (первое)
boo_boo_1

I ' мы пытались реализовать это решение, используя IEqualityComparer с:

public class MyEqualityComparer : IEqualityComparer<string>
{
    public bool Equals(string x, string y)
    {            
        int xIndex = x.LastIndexOf("_"); 
        int yIndex = y.LastIndexOf("_");
        if (xIndex > 0 && yIndex > 0)
            return x.Substring(0, xIndex) == y.Substring(0, yIndex);
        else
            return false;
    }

    public int GetHashCode(string obj)
    {
        return obj.GetHashCode();
    }
}

foreach (var key in myList.Distinct(new MyEqualityComparer()))
{
    Console.WriteLine(key)    
}

Но в результате получилось:

foo_boo_1
foo_boo_2
foo_boo_3
boo_boo_1

Использование IEqualityComparer Как удалить отдельные значения подстроки (foo_boo_2 и foo_boo_3)?

* Обратите внимание, что «настоящие» ключи намного длиннее, что-то вроде «1_0_8-B153_GF_6_2», поэтому я должен использовать LastIndexOf.

Ответы [ 3 ]

1 голос
/ 12 марта 2020

В вашей текущей реализации есть fl aws:

  1. И Equals, и GetHashCode должны никогда исключение (необходимо проверить null)
  2. Если Equals возвращает true для x и y, тогда GetHashCode(x) == GetHashCode(y). Пример счетчика равен "abc_1" и "abc_2".

Ошибка 2nd вполне может вызвать Distinct return неверные результаты (Distinct первое вычисление га sh).

Правильный код может выглядеть примерно так

public class MyEqualityComparer : IEqualityComparer<string> {
  public bool Equals(string x, string y) {            
    if (ReferenceEquals(x, y))
      return true;
    else if ((null == x) || (null == y))
      return false;

    int xIndex = x.LastIndexOf('_'); 
    int yIndex = y.LastIndexOf('_');

    if (xIndex >= 0)         
      return (yIndex >= 0) 
        ? x.Substring(0, xIndex) == y.Substring(0, yIndex)
        : false;
    else if (yIndex >= 0)         
      return false;
    else
      return x == y; 
  }

  public int GetHashCode(string obj) {
    if (null == obj)  
      return 0;

    int index = obj.LastIndexOf('_');

    return index < 0 
      ? obj.GetHashCode() 
      : obj.Substring(0, index).GetHashCode();
  }
}

Теперь вы готовы использовать его с Distinct:

   foreach (var key in myList.Distinct(new MyEqualityComparer())) {
     Console.WriteLine(key)    
   }
1 голос
/ 12 марта 2020

Для более краткого решения, которое не использует пользовательский IEqualityComparer<>, вы можете использовать GroupBy. Например:

var keys = new List<string>()
{
    "foo_boo_1",
    "foo_boo_2",
    "foo_boo_3",
    "boo_boo_1"
};

var distinct = keys
    .Select(k => new
    {
        original = k,
        truncated = k.Contains("_") ? k.Substring(0, k.LastIndexOf("_")) : k
    })
    .GroupBy(k => k.truncated)
    .Select(g => g.First().original);

Это выводит:

foo_boo_1

boo_boo_1

1 голос
/ 12 марта 2020

Ваш метод GetHashCode в вашем компараторе равенства возвращает код ha sh для всей строки, просто сделайте его sh подстрокой, например:

public int GetHashCode(string obj)
{
    var index = obj.LastIndexOf("_");
    return obj.Substring(0, index).GetHashCode();
}
...