如何使用LINQ重命名列表中的重复项

时间:2011-08-23 15:23:23

标签: c# linq

我需要一个唯一值列表。但可能是,列表中的值存在两次或更多次。 如果发生这种情况,我必须重命名该值,但重命名的值也可以在列表中。

可以使用LINQ查询重命名值,这样我就不需要子查询了吗?

示例1: 的: “一个”,“一个”,“两个”,“两个”,“三个” 的: “一个”,“一个”,“两个”,“两个”,“三个”

示例2: 的: “一一一_” 的: “一个”,“一个”,“一个__”

第3个“one”有2个下划线,因为第2个“one”被重命名为“one _”。

非常感谢您的想法...

3 个答案:

答案 0 :(得分:12)

我认为这不应该只使用linq查询来完成。如果我是你,我会使用HashSet并创建一个函数。像这样:

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;
    }
}

[编辑]

这可以作为扩展方法,所以你可以这样称呼它:myList.GetUnique();(或类似的东西)

[编辑2]

修正了更改迭代器变量的错误。

答案 1 :(得分:2)

我会创建一个像这样的新扩展方法:

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;
    }
}

这将采用任何字符串序列,并创建一个HashSet - 非常快,O(1) - 的值。如果该值已存在,则会附加“_”并再次尝试。一旦它有一个唯一的,就返回它。

答案 2 :(得分:1)

使用扩展方法:

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;
        }
    }
}

用法:

var test1 = new[] {"one","one","two","two","three"};
Console.WriteLine(String.Join(",",test1.Uniquify("_")));

实例:http://rextester.com/rundotnet?code=BYFVK87508

修改:使用while循环现在支持以前根据以下评论不支持的所有情况。