2009-01-18 55 views
63

tengo una lista de elementosCómo contar duplicados en la lista con LINQ

  • John Identificación
  • Matt Identificación
  • John Identificación
  • de Scott Identificación
  • Matt Identificación
  • John ID
  • Lucas ID

Quiero incluirlos de nuevo en una lista como tal, lo que también significa que quiero ordenar por el mayor número de duplicados.

  • John ID 3
  • Matt ID 2
  • de Scott ID 1
  • Lucas ID 1

Quisiera saber cómo puedo hacer esto con LINQ y C#.

Gracias Todo

editar el código 2 Mostrando:

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(); 

Esta consulta muestra estos resultados: tiempos mundo

  • 1 hola
  • 1 hola veces mundo
  • 1 Hola mundo.
  • veces mundo
  • 1 hola
  • veces mundo
  • 1 hola
  • 1 hola mundo
  • veces
  • 1 Hello World.
  • veces
  • 1 Hello World

Me da la cuenta y el nombre, pero no me da el ID del juego ....

debería mostrar:

  • 6 hello world times 234234
  • 2 Hello World. 23432432
+0

dados sus resultados es obvio que el programa trata a todos sus artículos como distintos - como ya he dicho, debe implementar requisitos personalizados comparer, de lo contrario no es posible seleccionar valores distintos – aku

Respuesta

87

Puede usar "agrupar por" + "ordenar por". Ver para más detalles 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); 
} 

En respuesta a this post (ahora suprimida):

Si usted tiene una lista de algunos objetos personalizados, entonces necesitará utilizar custom comparer o grupo de propiedad específica.

También la consulta no puede mostrar el resultado. Muéstranos el código completo para obtener una mejor ayuda.

Basado en su última actualización:

Tienes esta línea de código:

group xx by xx into g 

Desde XX es un sistema de objeto personalizado no sabe cómo comparar un elemento en contra de otro. Como ya escribí, debe guiar el compilador y proporcionar alguna propiedad que se utilizará en comparación de objetos o proporcionar comparador personalizado. Aquí está un ejemplo:

Nota que utilizo Foo.Name como clave - es decir, los objetos serán agrupados en función del valor de Nombre propiedad.

Hay un inconveniente: se tratan 2 objetos para duplicar en función de sus nombres, pero ¿qué pasa con Id? En mi ejemplo, simplemente tomo Id del primer objeto en un grupo. Si sus objetos tienen diferentes ID, puede ser un problema.

//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); 
} 
+0

simplemente mostrando los resultados en un repetidor personalizado .... –

+0

Scott, solo muestre su código – aku

+0

Hecho, Ahora puede echar un vistazo a lo que estoy viendo. –

36

ligeramente más corta versión mediante la cadena de métodos:

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); 
} 
+1

fácil de entender y funcionó muy bien –

+1

Definitivamente la mejor solución - ¡gracias! –

+0

Simplicidad con experiencia. – Hitsa00

4

Las otras soluciones utilizan GroupBy. GroupBy es lento (que contiene todos los elementos de la memoria), así que escribió mi propio método 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

Aquí está el programa completo Selecciona esta

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(); 
}   
3

También se puede hacer Diccionario:

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); 
     } 
Cuestiones relacionadas