代码之家  ›  专栏  ›  技术社区  ›  Shahar Shokrani

如何通过自定义子字符串等式仅迭代不同的字符串值

  •  0
  • Shahar Shokrani  · 技术社区  · 6 年前

    类似 this 问题,我试图只迭代给定字符串的子字符串的不同值,例如:

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

    所选不同值的输出 应该是 (选择第一个子字符串的不同值):

    foo_boo_1(第一个)
    boo_boo_1

    我试着去实现 this 使用 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)    
    }
    

    但结果是:


    福布斯2
    福布斯3
    boo_boo_1

    使用 IEqualityComparer 如何删除子字符串的不同值( foo_boo_2 foo_boo_3 )?

    *请注意,“真实”键要长得多,类似于“1_0_8-B153_GF_6_2”,因此我必须使用LastIndexOf。

    1 回复  |  直到 6 年前
        1
  •  1
  •   Shahar Shokrani    6 年前

    您当前的实现有一些缺陷 瑕疵 :

    1. 二者都 Equals GetHashCode 必须 从不 抛出异常 (你必须检查一下 null )
    2. 如果 等于 返回 true 对于 x y 然后 GetHashCode(x) == GetHashCode(y) . 反例 "abc_1" "abc_2" .

    这个 第二 错误很可能导致 Distinct 回来 错误的结果 ( 不同的 首先计算散列)。

    正确的代码可以是这样的

    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();
      }
    }
    

    现在你已经准备好使用它了 不同的 :

       foreach (var key in myList.Distinct(new MyEqualityComparer())) {
         Console.WriteLine(key)    
       }
    
        2
  •  1
  •   DavidG    6 年前

    你的 GetHashCode 方法返回整个字符串的哈希代码,只需对子字符串进行哈希,例如:

    public int GetHashCode(string obj)
    {
        var index = obj.LastIndexOf("_");
        return obj.Substring(0, index).GetHashCode();
    }
    
        3
  •  1
  •   Community Mohan Dere    6 年前

    以获得更简洁的解决方案,避免使用自定义 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);
    

    这将产生:

    福布斯1

    boo_boo_1