2010-10-01 30 views
8

Ich habe eine Liste:Zählen doppelte Nummern in einer Liste

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

Jetzt muß ich ein Programm machen, das die Doppel Zahlen berechnet. Eine Nummer ist doppelt, wenn die Nummer davor gleich ist. Ich hoffe, Sie verstehen. Also 1 ist doppelt, 4 ist doppelt und wir haben 2 Doppel in 7,7,7.

+1

Können Sie ein wenig mehr Informationen darüber, warum/wie? Fühlt sich an wie eine Hausaufgabe/Interviewfrage. Es wäre sehr einfach zu lösen, nur mit einer Schleife und vergleichen Sie vorher mit aktuellen und speichern/reset, wenn Übereinstimmung gefunden wird - nur ein bisschen zusätzliche Logik zu stoppen 7 gezählt 3 mal. Wenn Sie wollten, dass es in linq oder etwas gelöst wird, dann ist das interessanter. –

Antwort

26

Hier ist eine Lösung in LINQ:

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

Dies schafft eine weitere Sequenz, die durch das erste Element der Liste übersprungen, und dann findet Elemente von beiden Sequenzen, die denselben Index und den gleichen Wert haben. Es wird in linearer Zeit ausgeführt, aber nur, weil eine Liste O(1) Zugriff per Index bietet.

+2

A definitiv +1. Die Antwort ist prägnant, korrekt (nicht getestet, aber ich gehe das Risiko ein), sehr clever, und argumentierte richtig, warum es in linearer Zeit läuft. – Fede

+2

+1: Das ist sehr elegant! – RedFilter

+9

Stellen Sie sich vor, Sie kopieren das als Hausaufgabe und müssen es dann der Klasse (und dem Lehrer) erklären ... mwahahaha –

2

so etwas wie dies funktionieren kann:

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

EDIT:

der obige Code wird nicht das Ergebnis der OP wollte. Hier ist eine bearbeitete Version, die Inspiration von Ani eleganter Lösung nimmt unter: :)

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

Hier ist ein Ansatz, der relativ einfach ist, nur eine Iteration einmal über die Reihenfolge, und arbeitet mit jeder Sequenz (nicht nur aufgelistet):

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; 
     } 
    } 
} 

Hier ist eine andere, die in noch einfacher ist, dass es nur eine LINQ-Abfrage, aber es nutzt Nebenwirkungen in der Where-Klausel, die böse ist:

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

Eine dritte Alternative, die etwas sauberer ist, verwendet aber eine SelectConsecutive Methode, die im Grunde SelectPairs von this answer, aber umbenannt wird etwas klarer :)

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

Was meinst du "benutzt einen Nebeneffekt"? –

+2

Meine Augen bluten. –

+0

@Lasse: Guter Punkt. Ähm, ich habe meinen Plan geändert. Warte mal, und ich bringe die Nebeneffekt-Version zurück :) –

6

Jede gute Möglichkeiten, zu versuchen, scheint es zu tun zu finden, so hier ist ein wirklich schlechter Weg statt:

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; 

Bitte tun Sie es nicht so.

+0

haha, +1 für Sinn für Humor. Es ist Freitag immerhin –

+0

Danke. Ich war mir nicht sicher, ob ich nach unten gehen würde - Stimmen für eine schlechte Antwort oder eine Erhöhung, um zu sagen, dass es schlecht war. :-) – teedyay

+0

+1 Es ist keine ganz schlechte non-Linq Antwort abgesehen von der Ausnahme - Sie könnten ContainsKey oder TryGetValue verwenden, um die Ausnahme zu vermeiden, und es wäre in Ordnung. –

0

Hier gehen Sie mit der Antwort in 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

Ein Beispiel, dass (wahrscheinlich) eine bessere Leistung als Linq verwenden, ist allerdings wohl weniger elegant:

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

Sie könnten dies tun :

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

Das ist ein bisschen wie @ KJN Antwort, es sei denn ich denke, es ist das „Doppel“ und „zwei Doppel“ zum Ausdruck bringt Klausel in der Frage ein bisschen besser:

  1. Gruppe alle ganzen Zahlen zusammen
  2. in denen nur daran interessiert, die mehr als einmal erscheinen (g.Count() > 1)
  3. eine abgeflachte Liste der „Doppel“ wählen, die nach dem ersten zu sein (g.Skip(1))

PS: Wir nehmen hier an, dass GroupBy nicht zuerst die Liste sortieren, und wenn es der Fall ist, dass diese Art negativ durch eine vorsortierte Liste beeinflusst nicht ...

Verwandte Themen