Utilizzando LINQ, da a List<int>
, come posso recuperare un elenco che contiene voci ripetute più volte e i loro valori?
Utilizzando LINQ, da a List<int>
, come posso recuperare un elenco che contiene voci ripetute più volte e i loro valori?
Risposte:
Il modo più semplice per risolvere il problema è raggruppare gli elementi in base al loro valore, quindi selezionare un rappresentante del gruppo se nel gruppo sono presenti più elementi. In LINQ, questo si traduce in:
var query = lst.GroupBy(x => x)
.Where(g => g.Count() > 1)
.Select(y => y.Key)
.ToList();
Se vuoi sapere quante volte gli elementi vengono ripetuti, puoi usare:
var query = lst.GroupBy(x => x)
.Where(g => g.Count() > 1)
.Select(y => new { Element = y.Key, Counter = y.Count() })
.ToList();
Ciò restituirà un List
tipo anonimo e ogni elemento avrà le proprietà Element
e Counter
, per recuperare le informazioni necessarie.
E infine, se è un dizionario che stai cercando, puoi usare
var query = lst.GroupBy(x => x)
.Where(g => g.Count() > 1)
.ToDictionary(x => x.Key, y => y.Count());
Ciò restituirà un dizionario, con l'elemento come chiave e il numero di volte che viene ripetuto come valore.
code
for (int i = 0; i <duplicates.Count; i ++) {int duplicate = duplicates [i]; duplicatesLocation.Add (duplicato, nuovo Elenco <int> ()); for (int k = 0; k <hitsList.Length; k ++) {if (hitsList [k] .Contains (duplicate)) {duplicatesLocation.ElementAt (i) .Value.Add (k); }} // rimuove i duplicati secondo alcune regole. }code
Scopri se un enumerabile contiene duplicati :
var anyDuplicate = enumerable.GroupBy(x => x.Key).Any(g => g.Count() > 1);
Scopri se tutti i valori in un elenco sono unici :
var allUnique = enumerable.GroupBy(x => x.Key).All(g => g.Count() == 1);
Un altro modo è usare HashSet
:
var hash = new HashSet<int>();
var duplicates = list.Where(i => !hash.Add(i));
Se desideri valori univoci nell'elenco dei duplicati:
var myhash = new HashSet<int>();
var mylist = new List<int>(){1,1,2,2,3,3,3,4,4,4};
var duplicates = mylist.Where(item => !myhash.Add(item)).Distinct().ToList();
Ecco la stessa soluzione di un metodo di estensione generico:
public static class Extensions
{
public static IEnumerable<TSource> GetDuplicates<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> selector, IEqualityComparer<TKey> comparer)
{
var hash = new HashSet<TKey>(comparer);
return source.Where(item => !hash.Add(selector(item))).ToList();
}
public static IEnumerable<TSource> GetDuplicates<TSource>(this IEnumerable<TSource> source, IEqualityComparer<TSource> comparer)
{
return source.GetDuplicates(x => x, comparer);
}
public static IEnumerable<TSource> GetDuplicates<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> selector)
{
return source.GetDuplicates(selector, null);
}
public static IEnumerable<TSource> GetDuplicates<TSource>(this IEnumerable<TSource> source)
{
return source.GetDuplicates(x => x, null);
}
}
List<int> { 1, 2, 3, 4, 5, 2 }
come sorgente, il risultato è un IEnumerable<int>
elemento con il valore di 1
(dove il valore duplicato corretto è 2)
Console.WriteLine("Count: {0}", duplicates.Count());
direttamente sotto di essa e viene stampata 6
. A meno che non mi manchi qualcosa sui requisiti per questa funzione, dovrebbe esserci solo 1 articolo nella raccolta risultante.
ToList
per risolvere il problema, ma significa che il metodo viene eseguito non appena viene chiamato e non quando si esegue l'iterazione sui risultati.
var hash = new HashSet<int>();
var duplicates = list.Where(i => !hash.Add(i));
porterà a un elenco che include tutte le occorrenze di duplicati. Quindi se hai quattro occorrenze di 2 nella tua lista, la tua lista duplicata conterrà tre occorrenze di 2, poiché solo una delle 2 può essere aggiunta a HashSet. Se si desidera che l'elenco contenga valori univoci per ciascun duplicato, utilizzare invece questo codice:var duplicates = mylist.Where(item => !myhash.Add(item)).ToList().Distinct().ToList();
Puoi farlo:
var list = new[] {1,2,3,1,4,2};
var duplicateItems = list.Duplicates();
Con questi metodi di estensione:
public static class Extensions
{
public static IEnumerable<TSource> Duplicates<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> selector)
{
var grouped = source.GroupBy(selector);
var moreThan1 = grouped.Where(i => i.IsMultiple());
return moreThan1.SelectMany(i => i);
}
public static IEnumerable<TSource> Duplicates<TSource, TKey>(this IEnumerable<TSource> source)
{
return source.Duplicates(i => i);
}
public static bool IsMultiple<T>(this IEnumerable<T> source)
{
var enumerator = source.GetEnumerator();
return enumerator.MoveNext() && enumerator.MoveNext();
}
}
L'uso di IsMultiple () nel metodo Duplicati è più veloce di Count () perché non esegue l'iterazione dell'intera raccolta.
Count()
è pre-calcolato e la tua soluzione è probabilmente più lenta.
Count()
] è sostanzialmente diverso dall'iterare l'intero elenco. Count()
è pre-calcolato ma non ripetendo l'intera lista.
Ho creato un'estensione per rispondere a questo che potresti includerlo nei tuoi progetti, penso che questo ritorni il più dei casi quando cerchi duplicati in List o Linq.
Esempio:
//Dummy class to compare in list
public class Person
{
public int Id { get; set; }
public string Name { get; set; }
public string Surname { get; set; }
public Person(int id, string name, string surname)
{
this.Id = id;
this.Name = name;
this.Surname = surname;
}
}
//The extention static class
public static class Extention
{
public static IEnumerable<T> getMoreThanOnceRepeated<T>(this IEnumerable<T> extList, Func<T, object> groupProps) where T : class
{ //Return only the second and next reptition
return extList
.GroupBy(groupProps)
.SelectMany(z => z.Skip(1)); //Skip the first occur and return all the others that repeats
}
public static IEnumerable<T> getAllRepeated<T>(this IEnumerable<T> extList, Func<T, object> groupProps) where T : class
{
//Get All the lines that has repeating
return extList
.GroupBy(groupProps)
.Where(z => z.Count() > 1) //Filter only the distinct one
.SelectMany(z => z);//All in where has to be retuned
}
}
//how to use it:
void DuplicateExample()
{
//Populate List
List<Person> PersonsLst = new List<Person>(){
new Person(1,"Ricardo","Figueiredo"), //fist Duplicate to the example
new Person(2,"Ana","Figueiredo"),
new Person(3,"Ricardo","Figueiredo"),//second Duplicate to the example
new Person(4,"Margarida","Figueiredo"),
new Person(5,"Ricardo","Figueiredo")//third Duplicate to the example
};
Console.WriteLine("All:");
PersonsLst.ForEach(z => Console.WriteLine("{0} -> {1} {2}", z.Id, z.Name, z.Surname));
/* OUTPUT:
All:
1 -> Ricardo Figueiredo
2 -> Ana Figueiredo
3 -> Ricardo Figueiredo
4 -> Margarida Figueiredo
5 -> Ricardo Figueiredo
*/
Console.WriteLine("All lines with repeated data");
PersonsLst.getAllRepeated(z => new { z.Name, z.Surname })
.ToList()
.ForEach(z => Console.WriteLine("{0} -> {1} {2}", z.Id, z.Name, z.Surname));
/* OUTPUT:
All lines with repeated data
1 -> Ricardo Figueiredo
3 -> Ricardo Figueiredo
5 -> Ricardo Figueiredo
*/
Console.WriteLine("Only Repeated more than once");
PersonsLst.getMoreThanOnceRepeated(z => new { z.Name, z.Surname })
.ToList()
.ForEach(z => Console.WriteLine("{0} -> {1} {2}", z.Id, z.Name, z.Surname));
/* OUTPUT:
Only Repeated more than once
3 -> Ricardo Figueiredo
5 -> Ricardo Figueiredo
*/
}
Per trovare solo i valori duplicati:
var duplicates = list.GroupBy(x => x.Key).Any(g => g.Count() > 1);
Per esempio. var list = new [] {1,2,3,1,4,2};
quindi raggruppa raggrupperà i numeri con i loro tasti e manterrà il conteggio (numero di volte che è stato ripetuto) con esso. Successivamente, stiamo solo verificando i valori che si sono ripetuti più di una volta.
Per trovare solo i valori uniuqe:
var unique = list.GroupBy(x => x.Key).All(g => g.Count() == 1);
Per esempio. var list = new [] {1,2,3,1,4,2};
quindi raggruppa raggrupperà i numeri con i loro tasti e manterrà il conteggio (numero di volte che è stato ripetuto) con esso. Dopodiché, stiamo solo verificando i valori che hanno ripetuto solo una volta che i mezzi sono unici.
var unique = list.Distinct(x => x)
Set completo di estensioni Linq-SQL delle funzioni duplicate controllate in MS SQL Server. Senza usare .ToList () o IEnumerable. Queste query vengono eseguite in SQL Server anziché in memoria. . I risultati ritornano solo in memoria.
public static class Linq2SqlExtensions {
public class CountOfT<T> {
public T Key { get; set; }
public int Count { get; set; }
}
public static IQueryable<TKey> Duplicates<TSource, TKey>(this IQueryable<TSource> source, Expression<Func<TSource, TKey>> groupBy)
=> source.GroupBy(groupBy).Where(w => w.Count() > 1).Select(s => s.Key);
public static IQueryable<TSource> GetDuplicates<TSource, TKey>(this IQueryable<TSource> source, Expression<Func<TSource, TKey>> groupBy)
=> source.GroupBy(groupBy).Where(w => w.Count() > 1).SelectMany(s => s);
public static IQueryable<CountOfT<TKey>> DuplicatesCounts<TSource, TKey>(this IQueryable<TSource> source, Expression<Func<TSource, TKey>> groupBy)
=> source.GroupBy(groupBy).Where(w => w.Count() > 1).Select(y => new CountOfT<TKey> { Key = y.Key, Count = y.Count() });
public static IQueryable<Tuple<TKey, int>> DuplicatesCountsAsTuble<TSource, TKey>(this IQueryable<TSource> source, Expression<Func<TSource, TKey>> groupBy)
=> source.GroupBy(groupBy).Where(w => w.Count() > 1).Select(s => Tuple.Create(s.Key, s.Count()));
}
c'è una risposta ma non ho capito perché non funziona;
var anyDuplicate = enumerable.GroupBy(x => x.Key).Any(g => g.Count() > 1);
la mia soluzione è così in questa situazione;
var duplicates = model.list
.GroupBy(s => s.SAME_ID)
.Where(g => g.Count() > 1).Count() > 0;
if(duplicates) {
doSomething();
}