c# distinct List子字符串

本文关键字:字符串 string distinct List | 更新日期: 2023-09-27 18:18:53

我想从字符串列表中删除重复项。我通过使用distinct来做到这一点,但是我想在比较时忽略第一个字符。

我已经有一个删除重复的工作代码,但我的代码也删除每个字符串的第一个字符。

List<string> mylist = new List<string>();
List<string> newlist = 
  mylist.Select(e => e.Substring(1, e.Length - 1)).Distinct().ToList();

输入:"1","1 b","2 a","3 c"、"4 d"

输出:"A"、"B"、"C","D"

正确的输出:"1A"、"2B"、"3C"、"4D",无论"1A"还是"2A"将被删除

我想我很接近但是....任何输入是高度赞赏!

解决方案应该尽可能快地工作;)

c# distinct List<string>子字符串

您可以实现一个IEqualityComparer<string>,它将通过忽略第一个字母来比较您的字符串。然后将其传递给Distinct方法。

myList.Distinct(new MyComparer());

在MSDN上也有一个例子,向您展示了如何实现和使用Distinct的自定义比较器

您可以将除第一个字符外的所有字符都GroupBy,并取每个组的第一个字符:

List<string> result= mylist.GroupBy(s => s.Length < 2 ? s : s.Substring(1))
                           .Select(g => g.First())
                           .ToList();
结果:

Console.Write(string.Join(",", result)); // 1A,1B,3C,4D

无论"1A"还是"2A"将被删除

如果你改变主意,你必须用新的逻辑替换g.First()

然而,如果性能真的很重要,你想要删除哪个副本并不重要,你应该更喜欢Selman的方法,建议编写一个自定义的IEqualityComparer<string>。这将比我的GroupBy方法更有效,如果它的GetHashCode实现如下:

return (s.Length < 2 ? s : s.Substring(1)).GetHashCode();

我将建议一个简单的扩展,您可以在类似的情况下重用

public static IEnumerable<T> DistinctBy<T, U>(this IEnumerable<T> This, Func<T, U> keySelector)
{
    var set = new HashSet<U>();
    foreach (var item in This)
    {
        if (set.Add(keySelector(item)))
            yield return item;
    }
}

这就是Linq中Distinct的基本实现方式。

用法:

List<string> newlist = 
  mylist.DistinctBy(e => e.Substring(1, e.Length - 1)).ToList();

我知道答案已经给出了,但因为我一直在研究这个答案,所以我还是要把它贴出来,以防它有任何用处。

如果你真的想要大列表的最快解决方案,那么像这样的东西可能是最优的。不过,您需要做一些精确的计时来确定!

这种方法在比较或计算哈希码时不会产生任何额外的字符串拷贝:

using System;
using System.Collections.Generic;
using System.Linq;
namespace Demo
{
    internal static class Program
    {
        static void Main()
        {
            var myList = new List<string>
            {
                "1A",
                "1B",
                "2A",
                "3C",
                "4D"
            };
            var newList = myList.Distinct(new MyComparer());
            Console.WriteLine(string.Join("'n", newList));
        }
        sealed class MyComparer: IEqualityComparer<string>
        {
            public bool Equals(string x, string y)
            {
                if (x.Length != y.Length)
                    return false;
                if (x.Length == 0)
                    return true;
                return (string.Compare(x, 1, y, 1, x.Length) == 0);
            }
            public int GetHashCode(string s)
            {
                if (s.Length <= 1)
                    return 0;
                int result = 17;
                unchecked
                {
                    bool first = true;
                    foreach (char c in s)
                    {
                        if (first)
                            first = false;
                        else
                            result = result*23 + c;
                    }
                }
                return result;
            }
        }
    }
}