C# 如何使用LINQ重命名列表中的重复项
我需要一个唯一值的列表。但也可能是,这些值在列表中存在两次或两次以上。 如果发生这种情况,我必须重命名该值,但重命名后的值也可能在列表中 可以使用LINQ查询重命名这些值,这样我就不需要子查询了 例1: 之前: “一”、“一”、“二”、“二”、“三” 之后: “一”、“一”、“二”、“二”、“三” 例2: 之前: “一”、“一”、“一” 之后: “一”、“一”、“一” 第三个“一”有2个下划线,因为第二个“一”已重命名为“一”C# 如何使用LINQ重命名列表中的重复项,c#,linq,C#,Linq,我需要一个唯一值的列表。但也可能是,这些值在列表中存在两次或两次以上。 如果发生这种情况,我必须重命名该值,但重命名后的值也可能在列表中 可以使用LINQ查询重命名这些值,这样我就不需要子查询了 例1: 之前: “一”、“一”、“二”、“二”、“三” 之后: “一”、“一”、“二”、“二”、“三” 例2: 之前: “一”、“一”、“一” 之后: “一”、“一”、“一” 第三个“一”有2个下划线,因为第二个“一”已重命名为“一” 非常感谢您的建议……我认为这不应该仅仅通过linq查询来完成。如果我
非常感谢您的建议……我认为这不应该仅仅通过linq查询来完成。如果我是你,我会使用哈希集并创建一个函数。大概是这样的:
IEnumerable<String> GetUnique(IEnumerable<String> list) {
HashSet<String> itms = new HashSet<String>();
foreach(string itm in list) {
string itr = itm;
while(itms.Contains(itr)) {
itr = itr + "_";
}
itms.Add(itr);
yield return itr;
}
}
public static IEnumerable<string> Uniquifier(this IEnumerable<string> values)
{
if (values == null) throw new ArgumentNullException("values");
var unique = new HashSet<string>();
foreach(var item in values)
{
var newItem = item;
while(unique.Contains(newItem))
{
newItem += '_';
}
unique.Add(newItem);
yield return newItem;
}
}
IEnumerable GetUnique(IEnumerable列表){
HashSet itms=新HashSet();
foreach(列表中的字符串itm){
字符串itr=itm;
而(itms.Contains(itr)){
itr=itr+“u2;”;
}
itms.Add(itr);
收益率;
}
}
[编辑]
不过,这可以被做成一个扩展方法,所以您可以这样调用它:myList.GetUnique()代码>(或类似的东西)
[编辑2]
修复了迭代器变量被更改的错误。我将创建一个新的扩展方法,如下所示:
IEnumerable<String> GetUnique(IEnumerable<String> list) {
HashSet<String> itms = new HashSet<String>();
foreach(string itm in list) {
string itr = itm;
while(itms.Contains(itr)) {
itr = itr + "_";
}
itms.Add(itr);
yield return itr;
}
}
public static IEnumerable<string> Uniquifier(this IEnumerable<string> values)
{
if (values == null) throw new ArgumentNullException("values");
var unique = new HashSet<string>();
foreach(var item in values)
{
var newItem = item;
while(unique.Contains(newItem))
{
newItem += '_';
}
unique.Add(newItem);
yield return newItem;
}
}
公共静态IEnumerable Uniquifier(此IEnumerable值)
{
如果(value==null)抛出新的ArgumentNullException(“值”);
var unique=新的HashSet();
foreach(值中的var项)
{
var newItem=项目;
while(unique.Contains(newItem))
{
newItem+='389;';
}
唯一。添加(newItem);
收益返回新项目;
}
}
这将获取任何字符串序列,并创建一个值的哈希集(非常快,O(1))。如果该值已存在,则会附加一个“389;”并重试。一旦它有一个唯一的,就返回它。使用扩展方法:
public static class EnumerableExtensions
{
public static IEnumerable<string> Uniquify(this IEnumerable<string> enumerable, string suffix)
{
HashSet<string> prevItems = new HashSet<string>();
foreach(var item in enumerable)
{
var temp = item;
while(prevItems.Contains(temp))
{
temp += suffix;
}
prevItems.Add(temp);
yield return temp;
}
}
}
实例:
编辑:根据下面的评论,使用while循环现在支持以前不支持的所有情况。即将发布类似的内容!我唯一的建议是将它作为一个扩展方法,这样调用起来更容易一些,并且在构建要插入的候选字符串时使用StringBuilder
,以避免大量低效的字符串连接。@Alxandr:Darn,这是我两次在键入我自己的答案时被击败:-)我曾想过使用StringBuilder,但后来我想,通常情况下,您可能只会使用在末尾添加1或2“u”的列表;在这种情况下,我认为使用StringBuilder的收益超过了在while循环中调用ToString的成本。。。嗯,我只是觉得这不值得。@Alxandr:同意,因为每次查找都需要字符串,concat(+)更有效。@StriplingWarrior:等等,什么?你的意思是如果我做了string a=“a”;字符串b=“b”;字符串c=a+b代码>C#(幕后)创建用于连接的StringBuilder?这不是浪费了内存吗?LINQ不适合修改集合,但适合查询集合。我同意Alxandr的建议。@Jens:这并不要求修改TSource,只要求查询派生项。但是同意这个建议。你应该用哈希集来切换列表。速度快得多,算法错误。如果同一字符串值出现多次,则使用“一”、“一”、“一”
进行测试不起作用。这是实际编译并正确工作的第一个答案。