2010-11-05 8 views

risposta

3

Simile alla risposta di svick, se non con gli effetti collaterali per evitare i contro e invertire:

int[] source = new int[] { 1, 2, 3, 4, 4, 4, 5, 6, 7, 4, 4, 4, 8, 9, 4, 4, 4 }; 

List<int> result = new List<int> { source.First() }; 
source.Aggregate((acc, c) => 
    { 
     if (acc != c) 
      result.Add(c); 
     return c; 
    }); 

Edit: non ha più bisogno del source.First() come per la preoccupazione di mquander:

int[] source = new int[] { 1, 2, 3, 4, 4, 4, 5, 6, 7, 4, 4, 4, 8, 9, 4, 4, 4 }; 

List<int> result = new List<int>(); 
result.Add(
    source.Aggregate((acc, c) => 
    { 
     if (acc != c) 
      result.Add(acc); 
     return c; 
    }) 
); 

penso Mi piace ancora di più la soluzione di Danny.

+0

Sarebbe tutta questa soluzione eccetto che il primo .First() lo uccide per operare su qualsiasi sequenza pigra. – mquander

+0

Vero, hmm ...... –

+0

Eccoci, dai un'occhiata ora: D –

5

Non proprio. Mi piacerebbe scrivere questo:

public static IEnumerable<T> RemoveDuplicates(this IEnumerable<T> sequence) 
{ 
    bool init = false; 
    T current = default(T); 

    foreach (var x in sequence) 
    { 
     if (!init || !object.Equals(current, x)) 
      yield return x; 

     current = x; 
     init = true; 
    } 
} 
+2

+1, ma preferirei un nome migliore per il metodo ... 'RemoveDuplicates' è confuso perché sembra implicare che tutti i duplicati vengano rimossi, quando in realtà vengono rimossi solo * adiacenti * i duplicati. Forse qualcosa come 'RemoveAdjacentDuplicates' –

+0

Non sono d'accordo. Credo che ci sia un nome comune per questa operazione che non posso richiamare in questo momento. – mquander

+0

'RemoveRepeats'? –

1

È possibile utilizzare Aggregate() (anche se non sono sicuro se è meglio che la soluzione non LINQ):

var ints = new[] { 1, 2, 3, 4, 4, 4, 5, 6, 7, 4, 4, 4, 8, 9, 4, 4, 4 }; 

var result = ints.Aggregate(
    Enumerable.Empty<int>(), 
    (list, i) => 
     list.Any() && list.First() == i 
     ? list 
     : new[] { i }.Concat(list)).Reverse(); 

ho penso è O (n), ma non ne sono completamente sicuro.

+1

Creativo, ma difficilmente leggibile ... –

+0

Probabilmente lo stile più fedele a quello funzionale, però. In F # sarebbe qualcosa di simile a 'ints |> List.fold (fun (l, i) c -> if c <> i then (c :: l, c) else (l, c)) ([], ints.Head + 1) |> fst |> List.rev'. Ora, se c'è un modo per usare 'yield' o qualche altra forma di comprensione delle liste, siamo nel business. –

0

Se si utilizza .NET 4, è possibile farlo utilizzando il metodo integrato Zip, anche se probabilmente preferirei utilizzare un metodo di estensione personalizzato come quello mostrato in mquander's answer.

// replace "new int[1]" below with "new T[1]" depending on the type of element 
var filtered = original.Zip(new int[1].Concat(original), 
          (l, r) => new { L = l, R = r }) 
         .Where((x, i) => (i == 0) || !object.Equals(x.L, x.R)) 
         .Select(x => x.L); 
+0

Dovrebbe essere "Skip (1)", non "Take (1)" ... –

+0

@Thomas: No, "Take (1)" è ciò che intendevo. L'uso di 'Skip' invece si interrompe quando ci sono duplicati all'inizio della sequenza, ad esempio' {1, 1, 2} '. – LukeH

+0

Hai ragione, ho perso la parte Concat, quindi ho pensato che sarebbe tornato solo 1 articolo –

4

Sì, c'è! Codice a una riga e un loop della matrice.

int[] source = new int[] { 1, 2, 3, 4, 4, 4, 5, 6, 7, 4, 4, 4, 8, 9, 4, 4, 4 }; 
var result = source.Where((item, index) => index + 1 == source.Length 
          || item != source[index + 1]); 

E secondo @ consiglio di Hogan, può essere meglio:

var result = source.Where((item, index) => index == 0 
          || item != source[index - 1]); 

più leggibile ora penso. Significa "scegliere il primo elemento e quelli che non sono uguali a quello precedente".

+0

+1: buona soluzione. Meno leggibile di una soluzione non LINQ, ma LINQ è quello che l'OP ha richiesto, e questa è probabilmente la soluzione basata su LINQ più leggibile. –

+0

Divertente, in realtà penso che sia più leggibile. –

+0

Si presume che la raccolta di origine sia una matrice e questo è un problema banale da risolvere quando si ha accesso indicizzato e una proprietà 'Length'. Che ne dici di una soluzione che funziona su qualsiasi 'IEnumerable '? (Dopo tutto, la domanda parla di una sequenza, non di una lista o di un array.) – LukeH

Problemi correlati