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"将被删除
我想我很接近但是....任何输入是高度赞赏!
解决方案应该尽可能快地工作;)
您可以实现一个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;
}
}
}
}