Как считать дубликаты в списке с помощью LINQ - PullRequest
68 голосов
/ 18 января 2009

У меня есть список предметов

  • Джон ID
  • Мэтт ID
  • Джон ID
  • Скотт ID
  • Мэтт ID
  • Джон ID
  • Лукас ID

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

  • Джон ID 3
  • Matt ID 2
  • Скотт ID 1
  • Лукас ID 1

Дайте мне знать, как я могу это сделать с помощью LINQ и C #.

Спасибо всем

РЕДАКТИРОВАТЬ 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 Hello World.
  • 1 Hello World Times
  • 1 привет, мировое время
  • 1 привет, мировое время
  • 1 Hello World.
  • 1 привет миру раз

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

Должно отобразиться:

  • 6 Hello World Times 234234
  • 2 Hello World. 23432432

Ответы [ 5 ]

95 голосов
/ 18 января 2009

Вы можете использовать «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 в качестве ключа - то есть объекты будут сгруппированы на основе значения Name property.

Есть одна загвоздка - вы рассматриваете 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);
}
43 голосов
/ 18 января 2009

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

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);
}
7 голосов
/ 24 июня 2017

Вы также можете сделать словарь:

 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 голосов
/ 09 июля 2012

В других решениях используется 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;
}
0 голосов
/ 30 сентября 2016

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

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();
}        
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...