想要从列表中删除重复项,以便我的列表包含:
www.test.com
test.com
mytest.com
我希望最终列表如下所示(仅从前面的副本中选择带有www的域名):
www.test.com
mytest.com
我有这个linq,但似乎忽略了所有没有www的域名,因为它只选择了www:
var result=inputList.Where(x=>x.DomainName.StartsWith("www.")).Distinct();
修改
@DanielHilgarth:我只是运行你的代码并没有产生正确的结果。我有:
test.com
www.test.com
test2.com
www.test2.com
test3.com
www.test3.com
test4.com
在我的清单中。它返回:
test.com
www.test.com
www.test2.com
www.test3.com
以下是我如何使用您的代码:
var result = lstServerBindings.GroupBy(x => x.DomainName.StartsWith("www.") ? x.DomainName : "www." + x)
.Select(x =>
{
var domain =
x.FirstOrDefault(y => y.DomainName.StartsWith("www."));
if (domain == null)
return x.First();
return domain;
});
然后我做一个foreach循环来分配到新列表:
foreach (var item in result)
{
lstUniqueServerBindings.Add(new ServerBindings
{
IPAddress = item.IPAddress,
PortNumber = item.PortNumber,
DomainName = item.DomainName
});
}
答案 0 :(得分:5)
我想你想要这样的东西:
var result = domains.GroupBy(x => x.StartsWith("www.") ? x : "www." + x)
.Select(x =>
{
var domain =
x.FirstOrDefault(y => y.StartsWith("www."));
if(domain == null)
return x.First();
return domain;
});
我用这个输入测试了它:
var domains = new List<string>
{
"www.test.com",
"test.com",
"mytest.com",
"abc.com",
"www.abc.com"
};
结果是:
www.test.com
mytest.com
www.abc.com
您的代码应如下所示(请注意第二行末尾的其他.DomainName
):
var result = lstServerBindings.GroupBy(x => x.DomainName.StartsWith("www.") ?
x.DomainName : "www." + x.DomainName)
.Select(x =>
{
var domain =
x.FirstOrDefault(y =>
y.DomainName.StartsWith("www."));
if (domain == null)
return x.First();
return domain;
});
BTW:您可以通过将代码更改为此来保存自己的foreach循环:
var result = lstServerBindings.GroupBy(x => x.DomainName.StartsWith("www.") ?
x.DomainName : "www." + x.DomainName)
.Select(x =>
{
var item =
x.FirstOrDefault(y =>
y.DomainName.StartsWith("www."));
if (item == null)
item = x.First();
return new ServerBindings
{
IPAddress = item.IPAddress,
PortNumber = item.PortNumber,
DomainName = item.DomainName
};
});
答案 1 :(得分:1)
这是一个棘手的问题,但是有一个相当直接的解决方案:
public class wwwOrderComparison : IComparer<String>
{
public int Compare(string x, string y)
{
if(x == null && y == null)
return 0;
if(x == null ^ y == null)
return 0;
var xWww = x.StartsWith("www");
var yWww = y.StartsWith("www");
return (xWww && x == "www." + y) ? -1 : ((yWww && "www." + x == y) ? 1 : 0);
}
}
public class wwwEqualityComparison : IEqualityComparer<String>
{
public bool Equals(string x, string y)
{
if (x == null && y == null)
return true;
if (x == null ^ y == null)
return false;
var xWww = x.StartsWith("www");
var yWww = y.StartsWith("www");
if (xWww ^ yWww)
return xWww ? (x == "www." + y) : ("www." + x == y);
return xWww == yWww;
}
public int GetHashCode(string obj)
{
return (obj.StartsWith("www.") ? obj : ("www." + obj)).GetHashCode();
}
}
以下是测试:
var list = new List<String> {
"www.test.com",
"test.com",
"mytest.com",
"abc.com",
"www.abc.com",
"zzz.com",
"www.zzz.com"
};
var s = list.OrderBy(t => t, new wwwOrderComparison()).Distinct(new wwwEqualityComparison()).ToList();
这已通过我的所有测试。第二次干杯:)
答案 2 :(得分:0)
修改:请参阅下面的Daniel的回复。我对这个有点太匆匆了。
使用“选择”可以对元素进行投影,选择/修改某些属性。这可能听起来很复杂,但您需要做的就是:
inputList.Select(x => x.Replace("www.", "")).Distinct()
应该工作!
编辑:一点解释。使用select,您基本上可以将旧对象映射为新对象,然后为查询选择这些对象。在上面的情况下,您只选择一个简单的字符串对象,您可以创建一个全新的对象类型,类似于:
Select(x => new { Content = x, ContentLength = x.Length, ContentType = x.GetType() })
在这里,您可以根据输入对象的不同属性和方法动态构建一个新对象。选择是非常有用和强大的!
答案 3 :(得分:0)
重新定义平等意味着什么(通常是你在这里做的)的正常.NET方法是实现IEqualityComparer<T>
。
private class IgnoreWWWEqComparer : IEqualityComparer<string>
{
public bool Equals(string x, string y)
{
if(ReferenceEquals(x, y))
return true;
if(x == null || y == null)
return false;
if(x.StartsWith("www."))
{
if(y.StartsWith("www."))
return x.Equals(y);
return x.Substring(4).Equals(y);
//the above line can be made faster, but this is a reasonable
//approach if performance isn't critical
}
if(y.StartsWith("www."))
return x.Equals(y.Substring(4));
return x.Equals(y);
}
public int GetHashCode(string obj)
{
if(obj == null)
return 0;
if(obj.StartsWith("www."))
return obj.Substring(4).GetHashCode();
return obj.GetHashCode();
}
}
现在Distinct()
可以满足您的需求:
var result=inputList.OrderBy(s => !s.StartsWith("www.")).Distinct(new IgnoreWWWEqComparer());
对于一次性关闭,您可能会发现删除任何起始group by
的字符串www.
更方便,并选择每个分组的第一个,但上面应该更快地丢弃找到的重复,当然IgnoreWWWEqComparer
可以重复使用。
编辑:
考虑到“www。”的要求。表格优先,然后上面的情况很好,但是如果我们有一个非常大的列表可以处理的话,我会认为它会很糟糕。如果我们对性能非常苛刻,我们想让我们的Equals
和GetHashCode
变得更好,但是可能对大量列表进行排序对于几十个人来说可能会很好,但是在一段时间之后会开始受到伤害。因此,如果只有一个小数字(只是为了更简单),以下不是我采取的方法,但如果它可能非常大:
public static IEnumerable<string> FavourWWWDistinct(IEnumerable<string> src)
{
Dictionary<string, bool> dict = new Dictionary<string, bool>(new IgnoreWWWEqComparer());
foreach(string str in src)
{
bool withWWW;
if(dict.TryGetValue(str, out withWWW))
{
if(withWWW)
continue;
if(str.StartsWith("www."))
{
dict[str] = true;
yield return str;
}
}
else
{
if(dict[str] = str.StartsWith("www."))
yield return str;
}
}
foreach(var kvp in dict)
if(!kvp.Value)
yield return kvp.Key;
}
这样我们只要看到它们就会从"www."
开始传递这些表单,只有那些不以它开头的表单必须等待处理整个列表。