如何通过自定义子字符串相等性仅迭代不同的字符串值
How to iterate only distinct string values by custom substring equality
类似于this问题,我试图只迭代给定字符串的子字符串的不同值,例如:
List<string> keys = new List<string>()
{
"foo_boo_1",
"foo_boo_2,
"foo_boo_3,
"boo_boo_1"
}
selected 不同值的输出应该是(select 任意第一个子字符串的不同值):
foo_boo_1 (the first one)
boo_boo_1
我尝试使用 IEqualityComparer
实现 this 解决方案:
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
)?
*请注意 "real" 键要长很多,类似于“1_0_8-B153_GF_6_2”,因此我必须使用 LastIndexOf。
相等比较器中的 GetHashCode
方法返回整个字符串的哈希码,只需对其子字符串进行哈希处理即可,例如:
public int GetHashCode(string obj)
{
var index = obj.LastIndexOf("_");
return obj.Substring(0, index).GetHashCode();
}
您当前的实现有一些缺陷:
Equals
和 GetHashCode
必须 永远不会 抛出异常 (你必须检查 null
)
- 如果
Equals
returns true
对于 x
和 y
那么 GetHashCode(x) == GetHashCode(y)
。 反例是"abc_1"
和"abc_2"
。
第二个错误很可能导致Distinct
return不正确的结果(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();
}
}
现在您可以将它与 Distinct
一起使用了:
foreach (var key in myList.Distinct(new MyEqualityComparer())) {
Console.WriteLine(key)
}
要获得避免使用自定义 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
类似于this问题,我试图只迭代给定字符串的子字符串的不同值,例如:
List<string> keys = new List<string>()
{
"foo_boo_1",
"foo_boo_2,
"foo_boo_3,
"boo_boo_1"
}
selected 不同值的输出应该是(select 任意第一个子字符串的不同值):
foo_boo_1 (the first one)
boo_boo_1
我尝试使用 IEqualityComparer
实现 this 解决方案:
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
)?
*请注意 "real" 键要长很多,类似于“1_0_8-B153_GF_6_2”,因此我必须使用 LastIndexOf。
相等比较器中的 GetHashCode
方法返回整个字符串的哈希码,只需对其子字符串进行哈希处理即可,例如:
public int GetHashCode(string obj)
{
var index = obj.LastIndexOf("_");
return obj.Substring(0, index).GetHashCode();
}
您当前的实现有一些缺陷:
Equals
和GetHashCode
必须 永远不会 抛出异常 (你必须检查null
)- 如果
Equals
returnstrue
对于x
和y
那么GetHashCode(x) == GetHashCode(y)
。 反例是"abc_1"
和"abc_2"
。
第二个错误很可能导致Distinct
return不正确的结果(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();
}
}
现在您可以将它与 Distinct
一起使用了:
foreach (var key in myList.Distinct(new MyEqualityComparer())) {
Console.WriteLine(key)
}
要获得避免使用自定义 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