2008-10-13 7 views
5

Jak mogę wykonać metodę Ruby pod "Flatten" Ruby Method w języku C#. Metoda ta spłaszcza poszarpaną tablicę w jednowymiarową tablicę.Metoda spłaszczania Ruby w języku C#

Na przykład:

s = [ 1, 2, 3 ]   #=> [1, 2, 3] 
t = [ 4, 5, 6, [7, 8] ] #=> [4, 5, 6, [7, 8]] 
a = [ s, t, 9, 10 ]  #=> [[1, 2, 3], [4, 5, 6, [7, 8]], 9, 10] 
a.flatten     #=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10 
+0

Masz do czynienia z tablicami z postrzępionymi tablicami, a nie wielowymiarowymi. – leppie

+0

Wiwaty, mój błąd - posortowane. – chrisntr

Odpowiedz

12

Recursive rozwiązanie:

IEnumerable Flatten(IEnumerable array) 
{ 
    foreach(var item in array) 
    { 
     if(item is IEnumerable) 
     { 
      foreach(var subitem in Flatten((IEnumerable)item)) 
      { 
       yield return subitem; 
      } 
     } 
     else 
     { 
      yield return item; 
     } 
    } 
} 

EDIT 1:

Jon wyjaśnia w komentarzach, dlaczego nie może być metoda rodzajowa, spójrz!

EDIT 2:

Matt co sugeruje metodę rozszerzenia. Proszę, po prostu zastąpić pierwszy wiersz:

public static IEnumerable Flatten(this IEnumerable array) 

i można go używać tak:

foreach(var item in myArray.Flatten()) { ... } 
+1

Moja początkowa myśl brzmiała: "Dlaczego nie jest generyczna?" - ale oczywiście nie może być, ponieważ tylko bardzo rzadko jest to iterowalna wersja T również T. (np. IEnumerable jest nadal obiektem, ale IEnumerable nie jest ciągiem znaków.) Może warto to wyjaśnić w odpowiedzi. –

+0

Również nie jestem pewien, że istnieje sposób, aby zadeklarować silnie typed obdarty tablica w C# jest tam? Musi to być obiekt [], co oznacza, że ​​IEnumerable jest rozsądnym typem parametru dla tej metody. –

+0

Matt: Nie jesteś pewien, co masz na myśli, mówiąc o "silnie typowanej macierzowej tablicy", ale int [] [] i int [,] (odpowiednio dla poszarpanych i prostokątnych tablic int) są w porządku. –

2

odpowiedziałby mi w komentarzu, ale potrzebuję więcej niż 300 znaków.

@ Alexander rozwiązanie jest niesamowite, ale pojawia się problem z tablicami ciągów. Ponieważ string implementuje IEnumerable, myślę, że w końcu zwróci każdy znak w każdym ciągu. Można użyć parametru rodzajowego, aby poinformować go, jakie rzeczy masz nadzieję, że wrócił w tych przypadkach, np .:

public static IEnumerable Flatten<T>(IEnumerable e) 
{ 
    if (e == null) yield break; 
    foreach (var item in e) 
    { 
     if (item is T) 
      yield return (T)item; 
     else if (item is IEnumerable) 
     { 
      foreach (var subitem in Flatten<T>((IEnumerable)item)) 
       yield return subitem; 
     } 
     else 
      yield return item; 
    } 
}