如何使用Linq获取列表中字符串的位置出现?

时间:2018-12-16 07:32:42

标签: c# linq

var a = new List<string>() {"aa","aa","bb","bb","bb","cc","aa","aa","cc","cc" };

我想找到所有字符串的出现次数,对于上面的列表,我希望输出如下:

Index    String   Count
0        aa       2
2        bb       3
5        cc       1
6        aa       2
8        cc       2

但是当我尝试groupby时,它给出的总计数不是位置。 我怎么能得到这个?

  

编辑:我希望列表中超过1000万个条目。

2 个答案:

答案 0 :(得分:2)

您可以执行以下操作。

使用Linq的解决方案

var a = new List<string>() {"aa","aa","bb","bb","bb","cc","aa","aa","cc","cc" };
var result = Enumerable.Range(0, a.Count())
                    .Where(x => x == 0 || a[x - 1] != a[x])
                    .Select((x,index) => new Stat<string>
                            {
                                Index =index, 
                                StringValue = a[x], 
                                Count = a.Skip(x).TakeWhile(c => c == a[x]).Count() 
                            });

其中Stat定义为

public class Stat<T>
{
  public int Index{get;set;}
  public T StringValue {get;set;}
  public int Count {get;set;}
}

更新 使用迭代器

public IEnumerable<Stat<T>> CountOccurance<T>(IEnumerable<T> source)
{
    var lastItem = source.First();
    var count = 1;
    var index= 0;
    foreach(var item in source.Skip(1))
    {
        if(item.Equals(lastItem))
        {
            count++;
        }
        else
        {
            yield return new Stat<T>
            {
                Index = index,
                StringValue = lastItem,
                Count = count
            };
            count=1;
            lastItem = item;
            index++;
        }

    }

    yield return new Stat<T>
    {
        Index = index,
        StringValue = lastItem,
        Count = count
    }; 
}

然后您可以将结果提取为

var result = CountOccurance(a);

答案 1 :(得分:1)

如果您将多次使用此逻辑,则可以考虑编写自己的扩展方法。

public static class ExtensionMethods
{
    public static IEnumerable<SpecialGroup<TKey>> GroupAccordingToSuccessiveItems<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector)
    {
        int index = 0;
        int count = 0;

        TKey latestKey = default(TKey);

        foreach (var item in source)
        {
            TKey key = keySelector(item);


            if (index != 0 && !object.Equals(key, latestKey))
            {
                yield return new SpecialGroup<TKey>
                {
                    Index = index - count,
                    Obj = latestKey,
                    Count = count
                };

                count = 0;
            }

            latestKey = key;
            count++;
            index++;
        }

        yield return new SpecialGroup<TKey>
        {
            Index = index - count,
            Obj = latestKey,
            Count = count
        };
    }
}

public class SpecialGroup<T>
{
    public int Index { get; set; }
    public T Obj { get; set; }
    public int Count { get; set; }
}

然后您可以调用它,

var result =
            a.
            GroupAccordingToSuccessiveItems(i => i);

这将迭代所有列表一次。