2010-04-27 26 views
8

Tengo un List<string> que contiene duplicados y necesito encontrar los índices de cada uno.¿Cuál es la forma más elegante de encontrar el índice de elementos duplicados en C# List

¿Cuál es la forma más elegante y eficiente que no sea recorrer todos los elementos? Estoy en .NET 4.0 entonces LINQ es una opción. He hecho muchas búsquedas y me conecto para encontrar cualquier cosa.

datos de la muestra:

var data = new List<string>{"fname", "lname", "home", "home", "company"}(); 

necesito para obtener los índices de "casa".

+11

¿Cuántos artículos hay en la lista? ¿Está ordenado? ¿Es ordenable? ¿Cómo estás comparando por la igualdad? ¿Tiene que funcionar para cualquier tipo de datos o solo cadenas? ¿Por qué estás poniendo duplicados en la lista en primer lugar? Pediste lo más elegante Y más eficiente, pero a menudo son opuestos; ¿Cuál es realmente más importante? –

+1

¿Por qué dices "aparte de recorrer los elementos"? Alguien tiene que pasar por los elementos en algún momento, ya sea que usted o Linq lo hagan es seguramente irrelevante. – Stewart

Respuesta

19

Puede crear un objeto a partir de cada elemento que contenga su índice, luego agrupar en el valor y filtrar los grupos que contienen más de un objeto. Ahora usted tiene una lista que agrupa con los objetos que contienen el texto y su índice original:

var duplicates = data 
    .Select((t,i) => new { Index = i, Text = t }) 
    .GroupBy(g => g.Text) 
    .Where(g => g.Count() > 1); 
+0

¡Me gusta esta solución! ¡Fácil de leer y rápido! –

+0

Gracias esta fue la solución más elegante que pude encontrar –

3
using System; 
using System.Collections.Generic; 

class Program 
{ 
    static void Main(string[] args) 
    { 
     var data = new List<string> { "fname", "lname", "home", "home", "company" }; 
     foreach (var duplicate in FindDuplicates(data)) 
     { 
      Console.WriteLine("Duplicate: {0} at index {1}", duplicate.Item1, duplicate.Item2); 
     } 
    } 

    public static IEnumerable<Tuple<T, int>> FindDuplicates<T>(IEnumerable<T> data) 
    { 
     var hashSet = new HashSet<T>(); 
     int index = 0; 
     foreach (var item in data) 
     { 
      if (hashSet.Contains(item)) 
      { 
       yield return Tuple.Create(item, index); 
      } 
      else 
      { 
       hashSet.Add(item); 
      } 
      index++; 
     } 
    } 
} 
0

¿Qué tal algo como esto

var data = new List<string>{"fname", "lname", "home", "home", "company"}; 

      var duplicates = data 
          .Select((x, index) => new { Text = x, index}) 
          .Where(x => ( data 
              .GroupBy(i => i) 
              .Where(g => g.Count() > 1) 
              .Select(g => g.Key).ToList() 
             ).Contains(x.Text)); 
+0

Interresting, pero muy ineficiente. Debe crear la búsqueda una vez en vez de una por cada elemento de la lista. Para ser eficiente, la búsqueda debe ser un HashSet, no una lista. – Guffa

0

Yo mismo tenía que encontrar y eliminar los duplicados de la lista de instrumentos de cuerda. Primero busqué los índices de elementos duplicados y luego filtré la lista de manera funcional usando LINQ, sin mutar la lista original:

public static IEnumerable<string> RemoveDuplicates(IEnumerable<string> items) 
{ 
    var duplicateIndexes = items.Select((item, index) => new { item, index }) 
          .GroupBy(g => g.item) 
          .Where(g => g.Count() > 1) 
          .SelectMany(g => g.Skip(1), (g, item) => item.index); 
    return items.Where((item, index) => !duplicateIndexes.Contains(index)); 
} 
Cuestiones relacionadas