2010-10-01 4 views
8

J'ai une liste:Compter les numéros en double dans une liste

int list = { 1,1,2,3,4,4,5,7,7,7,10}; 

Maintenant, je dois faire un programme qui calcule les doubles chiffres. Un nombre est double lorsque le nombre avant est le même. J'espère que tu comprends. Donc 1 est double, 4 est double et nous avons 2 doubles en 7,7,7.

+1

Pouvez-vous fournir un peu plus d'informations sur pourquoi et comment? Se sent comme une question de devoir/entrevue. Il serait très simple de résoudre juste en utilisant une boucle et de comparer précédent à courant et stocker/réinitialiser si la correspondance est trouvée - juste un peu de logique supplémentaire pour arrêter 7 étant compté 3 fois. Si vous voulez qu'il soit résolu en linq ou quelque chose, c'est plus intéressant. –

Répondre

26

est ici une solution LINQ:

var doubles = list.Skip(1) 
        .Where((number, index) => list[index] == number); 

Cela crée une autre séquence en sautant le premier membre de la liste, et trouve ensuite des éléments des deux séquences qui ont le même indice et la même valeur. Il fonctionnera en temps linéaire, mais seulement parce qu'une liste offre O(1) accès par index.

+2

A définitivement +1. La réponse est concise, correcte (non testée, mais je prends le risque), très intelligente, et argumentée correctement pourquoi elle fonctionne en temps linéaire. – Fede

+2

+1: C'est très élégant! – RedFilter

+9

Imaginez que vous copiez cela comme une réponse aux devoirs, puis que vous deviez l'expliquer à la classe (et au professeur) ... mwahahaha –

2

quelque chose comme cela peut fonctionner:

list.GroupBy (l => l).Where (l => l.Count() > 1).SelectMany (l => l).Distinct(); 

EDIT:

le code ci-dessus ne soit pas le résultat de l'OP voulait. Voici une version modifiée qui prend l'inspiration de la solution élégante d'Ani ci-dessous: :)

list.GroupBy(l => l).Select(g=>g.Skip(1)).SelectMany (l => l); 
7

Voilà une approche qui est relativement simple, seulement itère une fois sur la séquence, et travaille avec une séquence (pas de listes seulement):

public IEnumerable<T> FindConsecutiveDuplicates<T>(this IEnumerable<T> source) 
{ 
    using (var iterator = source.GetEnumerator()) 
    { 
     if (!iterator.MoveNext()) 
     { 
      yield break; 
     } 
     T current = iterator.Current; 
     while (iterator.MoveNext()) 
     { 
      if (EqualityComparer<T>.Default.Equals(current, iterator.Current)) 
      { 
       yield return current; 
      } 
      current = iterator.Current; 
     } 
    } 
} 

est ici un autre qui est encore plus simple en ce qu'elle est seulement une requête LINQ, mais il utilise des effets secondaires dans la clause Where, qui est méchant:

IEnumerable<int> sequence = ...; 

bool first = true; 
int current = 0; 
var result = sequence.Where(x => { 
    bool result = !first && x == current; 
    current = x; 
    first = false; 
    return result; 
}); 

Une troisième alternative, qui est un peu plus propre mais utilise une méthode SelectConsecutive qui est essentiellement SelectPairs de this answer, mais renommé être un peu plus clair :)

IEnumerable<int> sequence = ...; 
IEnumerable<int> result = sequence.SelectConsecutive((x, y) => new { x, y }) 
            .Where(z => z.x == z.y); 
+2

Que voulez-vous dire "utilise un effet secondaire"? –

+2

Mes yeux saignent. –

+0

@Lasse: Bon point. Um, j'ai changé mon plan. Accrochez-vous, et je vais mettre la version à effet secondaire sauvegarder :) –

6

Tout le monde semble essayer de trouver de bonnes façons de le faire, donc Voici un très mauvais moyen à la place:

List<int> doubles = new List<int>(); 
Dictionary<int, bool> seenBefore = new Dictionary<int, bool>(); 

foreach(int i in list) 
{ 
    try 
    { 
     seenBefore.Add(i, true); 
    } 
    catch (ArgumentException) 
    { 
     doubles.Add(i); 
    } 
} 

return doubles; 

S'il vous plaît ne le faites pas comme ça.

+0

haha, +1 pour le sens de l'humour. C'est vendredi après tout –

+0

Merci. Je ne savais pas si je descendrais - votes pour avoir publié une mauvaise réponse ou avoir voté pour dire que c'était mauvais. :-) – teedyay

+0

+1 Ce n'est pas une mauvaise réponse non-Linq sauf l'exception - vous pouvez utiliser ContainsKey ou TryGetValue pour éviter l'exception et ce serait parfait. –

0

Ici vous allez avec la réponse en C# :)

int[] intarray = new int[] { 1, 1, 2, 3, 4, 4, 5, 7, 7, 7, 10 }; 

int previousnumber = -1; 
List<int> doubleDigits = new List<int>(); 
for (int i = 0; i < intarray.Length; i++) 
{ 
    if (previousnumber == -1) { previousnumber = intarray[i]; continue; } 
    if (intarray[i] == previousnumber) 
    { 
     if (!doubleDigits.Contains(intarray[i])) 
     { 
      doubleDigits.Add(intarray[i]); 
      //Console.WriteLine("Duplicate int found - " + intarray[i]); 
      continue; 
     } 
    } 
    else 
    { 
     previousnumber = intarray[i]; 
    } 
} 
0

Un exemple qui (probablement) fonctionne mieux que LINQ, mais est sans doute moins élégante:

for (int i = 1; i < list.Count; i++) 
    if (list[i] == list[i - 1]) 
     doubles.Add(list[i]); 
0

Vous pouvez le faire :

list.GroupBy(i => i).Where(g => g.Count() > 1).SelectMany(g => g.Skip(1)) 

Ceci est un peu comme la réponse de @ kjn, sauf que je pense qu'il exprime l'article « double » et « deux doubles » dans la question un peu mieux:

    groupe
  1. tous les entiers ensemble
  2. uniquement de ceux qui apparaissent plus d'une fois (g.Count() > 1)
  3. sélectionner une liste aplaties des « doubles », étant ceux après la première (g.Skip(1))

PS: Nous partons du principe ici, que GroupBy ne pas d'abord trier la liste et si elle le fait, que ce genre ne soit pas influencée négativement par une liste pré-triés ...

Questions connexes