Linq 拥有一份清单<;字符串>;如果行可以是相同的值,如何添加一个int使每行都是唯一的?

Linq 拥有一份清单<;字符串>;如果行可以是相同的值,如何添加一个int使每行都是唯一的?,linq,c#-4.0,lambda,Linq,C# 4.0,Lambda,我有一个列表,当几个项目具有相同的名称时,我想在其中添加一个内部计数器 var myList = new List<string>(); myList.Add("a"); myList.Add("b"); myList.Add("b"); myList.Add("c"); var myList=new List(); myList.添加(“a”); myList.添加(“b”); myList.添加(“b”); myList.添加(“c”); 我希望结果是 a01 b01 b0

我有一个列表,当几个项目具有相同的名称时,我想在其中添加一个内部计数器

var myList = new List<string>();

myList.Add("a");
myList.Add("b");
myList.Add("b");
myList.Add("c");
var myList=new List();
myList.添加(“a”);
myList.添加(“b”);
myList.添加(“b”);
myList.添加(“c”);
我希望结果是 a01 b01 b02 c01 在一些花哨的林克舞之后


有什么好主意吗?

如果你想保持秩序,在OOTB LINQ中没有令人惊讶的好方法,但是你可以这样做

var res =
    myList
        .GroupBy(item => item)
        .Select(item => String.Format("{0}{1}", item.Key, item.Count()));
public static IEnumerable<TResult> SelectWithUniquifier<TSource, TResult>(
    this IEnumerable<TSource> source, Func<TSource, int, TResult> uniquifier)
{
     Dictionary<TSource, int> counter = new Dictionary<TSource, int>();
     foreach(TSource s in source)
     {
         int thisIndex = counter.ContainsKey(s) ? counter[s] : 0;
         counter[s] = thisIndex + 1;
         yield return uniquifier(s, thisIndex);
     }
}

因为您得到的索引是以零为基础的。

如果您想保持顺序,在OOTB LINQ中没有令人惊讶的好方法来做到这一点,但是您可以像

public static IEnumerable<TResult> SelectWithUniquifier<TSource, TResult>(
    this IEnumerable<TSource> source, Func<TSource, int, TResult> uniquifier)
{
     Dictionary<TSource, int> counter = new Dictionary<TSource, int>();
     foreach(TSource s in source)
     {
         int thisIndex = counter.ContainsKey(s) ? counter[s] : 0;
         counter[s] = thisIndex + 1;
         yield return uniquifier(s, thisIndex);
     }
}

因为您得到的索引是基于零的。

并不是说这很好,但它是一个(主要)Linq解决方案:

var indexed =   from index in myList.Aggregate(
                    new 
                    { 
                        Counters = new Dictionary<string, int>(), 
                        Items = new List<string>() 
                    }, 
                    (acc, cur) => 
                    { 
                        if (!acc.Counters.ContainsKey(cur))
                            acc.Counters.Add(cur, 0);
                        acc.Counters[cur] = acc.Counters[cur] + 1;
                        acc.Items.Add(cur + acc.Counters[cur]);
                        return acc;
                    }).Items
                select index;
var index=myList.Aggregate中的索引(
新的
{ 
计数器=新字典(),
Items=新列表()
}, 
(acc,cur)=>
{ 
如果(!acc.Counters.ContainsKey(cur))
附件计数器添加(当前,0);
附件计数器[cur]=附件计数器[cur]+1;
附件项目添加(当前+附件计数器[cur]);
返回acc;
}).项目
选择索引;
累加部分非常难看,但它在Linq计算中完成了这项工作

编辑

如果初始列表已排序,则此表达式更干净(但可能效率低下,您必须查看列表中有多少项):

var index=myList.Aggregate中的索引(
新的
{ 
计数器=0,
Key=(字符串)null,
Items=可枚举的.Empty()
}, 
(acc,cur)=>
{
var计数器=附件键!=电流?1:附件计数器+1;
还新
{ 
计数器=计数器,
Key=cur,
项目=acc.Items.Concat(
可枚举。重复(cur+计数器,1))
};
}).项目
选择索引;

并不是说这很好,但这是一个(主要)Linq解决方案:

var indexed =   from index in myList.Aggregate(
                    new 
                    { 
                        Counters = new Dictionary<string, int>(), 
                        Items = new List<string>() 
                    }, 
                    (acc, cur) => 
                    { 
                        if (!acc.Counters.ContainsKey(cur))
                            acc.Counters.Add(cur, 0);
                        acc.Counters[cur] = acc.Counters[cur] + 1;
                        acc.Items.Add(cur + acc.Counters[cur]);
                        return acc;
                    }).Items
                select index;
var index=myList.Aggregate中的索引(
新的
{ 
计数器=新字典(),
Items=新列表()
}, 
(acc,cur)=>
{ 
如果(!acc.Counters.ContainsKey(cur))
附件计数器添加(当前,0);
附件计数器[cur]=附件计数器[cur]+1;
附件项目添加(当前+附件计数器[cur]);
返回acc;
}).项目
选择索引;
累加部分非常难看,但它在Linq计算中完成了这项工作

编辑

如果初始列表已排序,则此表达式更干净(但可能效率低下,您必须查看列表中有多少项):

var index=myList.Aggregate中的索引(
新的
{ 
计数器=0,
Key=(字符串)null,
Items=可枚举的.Empty()
}, 
(acc,cur)=>
{
var计数器=附件键!=电流?1:附件计数器+1;
还新
{ 
计数器=计数器,
Key=cur,
项目=acc.Items.Concat(
可枚举。重复(cur+计数器,1))
};
}).项目
选择索引;

请参阅其他答案,了解一些奇特(且相当令人困惑)的LINQ解决方案。如果您不一定需要使用LINQ:

var myList = new List<string> { "a", "b", "c", "b" };

var counter = new ConcurrentDictionary<string, int>();
for (int i = 0; i < myList.Count; i++)
{
    var currVal = myList[i];
    counter.AddOrUpdate(currVal, 1, (value, count) => count + 1);
    myList[i] = currVal + counter[currVal].ToString("00");
}
var myList=新列表{“a”、“b”、“c”、“b”};
var计数器=新的ConcurrentDictionary();
for(int i=0;icount+1);
myList[i]=currVal+计数器[currVal].ToString(“00”);
}
不需要ConcurrentDictionary
,您可以手动执行“添加或更新”操作,具体取决于您对速度和代码清晰度的评价。不管是哪种方式,在我看来,这是一种更具可读性和可维护性的方式来做你想做的事情。不要害怕你的老朋友。:)


当然,这可以作为一个扩展方法,或者某个实用程序类上的静态方法等来实现。

请参阅其他答案,以了解一些奇特(而且相当混乱)的LINQ解决方案。如果您不一定需要使用LINQ:

var myList = new List<string> { "a", "b", "c", "b" };

var counter = new ConcurrentDictionary<string, int>();
for (int i = 0; i < myList.Count; i++)
{
    var currVal = myList[i];
    counter.AddOrUpdate(currVal, 1, (value, count) => count + 1);
    myList[i] = currVal + counter[currVal].ToString("00");
}
var myList=新列表{“a”、“b”、“c”、“b”};
var计数器=新的ConcurrentDictionary();
for(int i=0;icount+1);
myList[i]=currVal+计数器[currVal].ToString(“00”);
}
不需要ConcurrentDictionary
,您可以手动执行“添加或更新”操作,具体取决于您对速度和代码清晰度的评价。不管是哪种方式,在我看来,这是一种更具可读性和可维护性的方式来做你想做的事情。不要害怕你的老朋友。:)

当然,这可以作为一个扩展方法,或某个实用程序类上的静态方法等来完成。

另一种更简单的方法:

  var result = myList.GroupBy(x => x)
            .SelectMany(g => g.Select((x, i) => x + (i + 1).ToString("00")));
另一种更简单的方法:

  var result = myList.GroupBy(x => x)
            .SelectMany(g => g.Select((x, i) => x + (i + 1).ToString("00")));