Как подсчитать дубликаты в списке с помощью LINQ

У меня есть список элементов

  • John ID
  • Матовый идентификатор
  • John ID
  • Скотт ID
  • Матовый идентификатор
  • John ID
  • Lucas ID

Я хочу перетащить их обратно в список вроде этого, что также означает, что я хочу сортировать по самому большому количеству дубликатов.

  • John ID 3
  • Matt ID 2
  • Скотт ID 1
  • Lucas ID 1

Сообщите мне, как я могу это сделать с LINQ и С#.

Спасибо всем

РЕДАКТИРОВАТЬ 2 Показывать код:

    List<game> inventory = new List<game>();
    drinkingforDataContext db = new drinkingforDataContext();
    foreach (string item in tbTitle.Text.Split(' '))
    {

        List<game> getItems = (from dfg in db.drinkingfor_Games
                               where dfg.game_Name.Contains(tbTitle.Text)
                               select new game
                               {
                                   gameName = dfg.game_Name,
                                   gameID = Boomers.Utilities.Guids.Encoder.EncodeURLs(dfg.uid)
                               }).ToList<game>();

        for (int i = 0; i < getItems.Count(); i++)
        {
            inventory.Add(getItems[i]);
        }
    }

    var items = (from xx in inventory
                 group xx by xx into g
                 let count = g.Count()
                 orderby count descending
                 select new
                    {
                        Count = count,
                        gameName = g.Key.gameName,
                        gameID = g.Key.gameID
                    });

    lvRelatedGames.DataSource = items;
    lvRelatedGames.DataBind();

В этом запросе отображаются следующие результаты:

  • 1 привет мировые времена
  • 1 привет мировые времена
  • 1 Привет, мир.
  • 1 привет мировые времена
  • 1 привет мировые времена
  • 1 привет мировые времена
  • 1 Привет, мир.
  • 1 привет мировые времена

Это дает мне счет и имя, но это не дает мне идентификатор игры....

Он должен отображать:

  • 6 привет мировые времена 234234
  • 2 Привет, мир. 23432432

Ответ 1

Вы можете использовать "group by" + "orderby". Подробнее см. LINQ 101

var list = new List<string> {"a", "b", "a", "c", "a", "b"};
var q = from x in list
        group x by x into g
        let count = g.Count()
        orderby count descending
        select new {Value = g.Key, Count = count};
foreach (var x in q)
{
    Console.WriteLine("Value: " + x.Value + " Count: " + x.Count);
}

В ответ на этот пост (теперь удален):

Если у вас есть список некоторых пользовательских объектов, вам нужно использовать пользовательский сопоставитель или группу по определенному свойству.

Также запрос не может отобразить результат. Покажите нам полный код, чтобы получить лучшую помощь.

На основе вашего последнего обновления:

У вас есть эта строка кода:

group xx by xx into g

Так как xx - это система пользовательских объектов, она не знает, как сравнивать один элемент с другим. Как я уже писал, вам необходимо направить компилятор и предоставить некоторое свойство, которое будет использоваться при сравнении объектов или предоставить пользовательский сопоставитель. Вот пример:

Обратите внимание, что я использую Foo.Name как ключ - т.е. объекты будут сгруппированы на основе значения свойства Имя.

Есть один улов - вы обрабатываете 2 объекта, которые должны дублироваться на основе их имен, но как насчет Id? В моем примере я просто беру идентификатор первого объекта в группе. Если ваши объекты имеют разные идентификаторы, это может быть проблемой.

//Using extension methods
var q = list.GroupBy(x => x.Name)
            .Select(x => new {Count = x.Count(), 
                              Name = x.Key, 
                              ID = x.First().ID})
            .OrderByDescending(x => x.Count);

//Using LINQ
var q = from x in list
        group x by x.Name into g
        let count = g.Count()
        orderby count descending
        select new {Name = g.Key, Count = count, ID = g.First().ID};

foreach (var x in q)
{
    Console.WriteLine("Count: " + x.Count + " Name: " + x.Name + " ID: " + x.ID);
}

Ответ 2

Немного короче версия, использующая цепочку методов:

var list = new List<string> {"a", "b", "a", "c", "a", "b"};
var q = list.GroupBy(x => x)
            .Select(g => new {Value = g.Key, Count = g.Count()})
            .OrderByDescending(x=>x.Count);

foreach (var x in q)
{
    Console.WriteLine("Value: " + x.Value + " Count: " + x.Count);
}

Ответ 3

В других решениях используется GroupBy. GroupBy медленный (он содержит все элементы в памяти), поэтому я написал свой собственный метод CountBy:

public static Dictionary<TKey,int> CountBy<TSource,TKey>(this IEnumerable<TSource> source, Func<TSource,TKey> keySelector)
{
    var countsByKey = new Dictionary<TKey,int>();
    foreach(var x in source)
    {
        var key = keySelector(x);
        if (!countsByKey.ContainsKey(key))
            countsByKey[key] = 0;
        countsByKey[key] += 1;
    }
    return countsByKey;
}

Ответ 4

Вы также можете использовать словарь:

 var list = new List<string> { "a", "b", "a", "c", "a", "b" };
 var result = list.GroupBy(x => x)
            .ToDictionary(y=>y.Key, y=>y.Count())
            .OrderByDescending(z => z.Value);

 foreach (var x in result)
        {
            Console.WriteLine("Value: " + x.Key + " Count: " + x.Value);
        }

Ответ 5

Вот полная программа, пожалуйста, проверьте

static void Main(string[] args)
{
    List<string> li = new List<string>();
    li.Add("Ram");
    li.Add("shyam");
    li.Add("Ram");
    li.Add("Kumar");
    li.Add("Kumar");

    var x = from obj in li group obj by obj into g select new { Name = g.Key, Duplicatecount = g.Count() };
    foreach(var m in x)
    {
        Console.WriteLine(m.Name + "--" + m.Duplicatecount);
    }
    Console.ReadLine();
}