How to rename duplicates in list using LINQ
I need a list of unique values. But it could be, the values exists twice or more in the list. If this occurs I must rename the value but the renamed value also could be in the list.
It is pos开发者_StackOverflow中文版sible to rename the values using a LINQ query so i don't need a sub-query?
example 1: before: "one", "one", "two", "two", "three" after: "one", "one_", "two", "two_", "three"
example 2: before: "one", "one", "one_" after: "one", "one_", "one__"
The 3rd "one" has 2 underscores because the 2nd "one" was renamed to "one_".
Thanks a lot for an idea...
I don't think this should be done with simply a linq-query. I'd use a HashSet and create a function if I was you. Something like this:
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;
}
}
[Edit]
This could be made into an extension-method though, so you could call it like this: myList.GetUnique();
(or something like that)
[Edit 2]
Fixed bug with iterator-variable being changed.
I would create a new extension method like this:
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;
}
}
This will take any sequence of string, and create a HashSet - very fast, O(1) - of the values. If the value already exists, it appends a '_' and tries again. Once it has one unique, returns it.
Using an extension method:
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;
}
}
}
usage:
var test1 = new[] {"one","one","two","two","three"};
Console.WriteLine(String.Join(",",test1.Uniquify("_")));
Live example: http://rextester.com/rundotnet?code=BYFVK87508
Edit: Using the while loop now supports all cases previously unsupported as per comments below.
精彩评论