registros - buscar elementos repetidos en una lista c#
¿Cómo obtener elementos duplicados de una lista usando LINQ? (9)
Tengo una List<string>
como:
List<String> list = new List<String>{"6","1","2","4","6","5","1"};
Necesito obtener los elementos duplicados en la lista en una nueva lista. Ahora estoy usando un ciclo anidado for
hacer esto.
La list
resultante contendrá {"6","1"}
.
¿Hay alguna idea para hacer esto usando expresiones LINQ o lambda ?
Aquí hay otra opción:
var list = new List<string> { "6", "1", "2", "4", "6", "5", "1" };
var set = new HashSet<string>();
var duplicates = list.Where(x => !set.Add(x));
Aquí hay una manera de hacerlo:
List<String> duplicates = lst.GroupBy(x => x)
.Where(g => g.Count() > 1)
.Select(g => g.Key)
.ToList();
El GroupBy
agrupa los elementos que son iguales, y Where
filtra aquellos que solo aparecen una vez, dejándote solo con los duplicados.
Escribí este método de extensión basado en la respuesta de @ Lee al OP. Tenga en cuenta que se utilizó un parámetro predeterminado (que requiere C # 4.0). Sin embargo, una llamada al método sobrecargado en C # 3.0 sería suficiente.
/// <summary>
/// Method that returns all the duplicates (distinct) in the collection.
/// </summary>
/// <typeparam name="T">The type of the collection.</typeparam>
/// <param name="source">The source collection to detect for duplicates</param>
/// <param name="distinct">Specify <b>true</b> to only return distinct elements.</param>
/// <returns>A distinct list of duplicates found in the source collection.</returns>
/// <remarks>This is an extension method to IEnumerable<T></remarks>
public static IEnumerable<T> Duplicates<T>
(this IEnumerable<T> source, bool distinct = true)
{
if (source == null)
{
throw new ArgumentNullException("source");
}
// select the elements that are repeated
IEnumerable<T> result = source.GroupBy(a => a).SelectMany(a => a.Skip(1));
// distinct?
if (distinct == true)
{
// deferred execution helps us here
result = result.Distinct();
}
return result;
}
Espero que esto ayude
int[] listOfItems = new[] { 4, 2, 3, 1, 6, 4, 3 };
var duplicates = listOfItems
.GroupBy(i => i)
.Where(g => g.Count() > 1)
.Select(g => g.Key);
foreach (var d in duplicates)
Console.WriteLine(d);
Estaba tratando de resolver el problema con una lista de objetos y estaba teniendo problemas porque estaba tratando de volver a empaquetar la lista de grupos en la lista original. Así que se me ocurrió pasar por los grupos para volver a empaquetar la Lista original con los elementos que tienen duplicados.
public List<MediaFileInfo> GetDuplicatePictures()
{
List<MediaFileInfo> dupes = new List<MediaFileInfo>();
var grpDupes = from f in _fileRepo
group f by f.Length into grps
where grps.Count() >1
select grps;
foreach (var item in grpDupes)
{
foreach (var thing in item)
{
dupes.Add(thing);
}
}
return dupes;
}
Sé que no es la respuesta a la pregunta original, pero puede que te encuentres aquí con este problema.
Si desea todos los elementos duplicados en sus resultados, lo siguiente funciona.
var duplicates = list
.GroupBy( x => x ) // group matching items
.Where( g => g.Skip(1).Any() ) // where the group contains more than one item
.SelectMany( g => g ); // re-expand the groups with more than one item
En mi situación, necesito todos los duplicados para poder marcarlos en la interfaz de usuario como si fueran errores.
Todas las soluciones mencionadas hasta ahora realizan un GroupBy. Incluso si solo necesito el primer duplicado, todos los elementos de las colecciones se enumeran al menos una vez.
La siguiente función de extensión deja de enumerar tan pronto como se encuentra un duplicado. Continúa si se solicita un próximo duplicado.
Como siempre en LINQ, hay dos versiones, una con IEqualityComparer y otra sin ella.
public static IEnumerable<TSource> ExtractDuplicates(this IEnumerable<TSource> source)
{
return source.ExtractDuplicates(null);
}
public static IEnumerable<TSource> ExtractDuplicates(this IEnumerable<TSource source,
IEqualityComparer<TSource> comparer);
{
if (source == null) throw new ArgumentNullException(nameof(source));
if (comparer == null)
comparer = EqualityCompare<TSource>.Default;
HashSet<TSource> foundElements = new HashSet<TSource>(comparer);
foreach (TSource sourceItem in source)
{
if (!foundElements.Contains(sourceItem))
{ // we''ve not seen this sourceItem before. Add to the foundElements
foundElements.Add(sourceItem);
}
else
{ // we''ve seen this item before. It is a duplicate!
yield return sourceItem;
}
}
}
Uso:
IEnumerable<MyClass> myObjects = ...
// check if has duplicates:
bool hasDuplicates = myObjects.ExtractDuplicates().Any();
// or find the first three duplicates:
IEnumerable<MyClass> first3Duplicates = myObjects.ExtractDuplicates().Take(3)
// or find the first 5 duplicates that have a Name = "MyName"
IEnumerable<MyClass> myNameDuplicates = myObjects.ExtractDuplicates()
.Where(duplicate => duplicate.Name == "MyName")
.Take(5);
Para todas estas sentencias linq, la colección solo se analiza hasta que se encuentran los elementos solicitados. El resto de la secuencia no se interpreta.
En mi humilde opinión es un impulso de eficiencia a considerar.
List<String> list = new List<String> { "6", "1", "2", "4", "6", "5", "1" };
var q = from s in list
group s by s into g
where g.Count() > 1
select g.First();
foreach (var item in q)
{
Console.WriteLine(item);
}
var duplicates = lst.GroupBy(s => s)
.SelectMany(grp => grp.Skip(1));
Tenga en cuenta que esto devolverá todos los duplicados, por lo que si solo desea saber qué elementos están duplicados en la lista fuente, puede aplicar Distinct
a la secuencia resultante o utilizar la solución proporcionada por Mark Byers.