2011-08-05 18 views
10

Aşağıdakileri daha basit bir şekilde yapmamı sağlayan süslü bir LINQ ifadesi var mı? Listenin 2d matrisinde sütunlar olduğunu varsayarak, sütunların listesini satırlar listesine takmak istiyorum, bir List<List<double>> var. Aşağıdaki bariz bir çözüm vardır:LINQ sütunları satırlara takas

İşte
int columns = 5; 
var values; // assume initialised as List<List<double>>() 

var listOfRows = new List<List<double>>(); 
for (int i = 0; i < columns ; i++) 
{ 
    List<double> newRow = new List<double>(); 
    foreach (List<double> value in values) 
    { 
     newRow.Add(value[i]); 
    } 
    listOfRows.Add(newRow); 
} 

cevap

5

Oldukça kolay iç döngü LINQify olabilir:

o okunabilirliği artırır olsun ya da olmasın vector.AddRange(values.Select(value => value[i]));

tamamen size bırakılmıştır!

+0

@ DBM: tanım nedir? AddRange? –

+0

@ Reb.Cabin: http://msdn.microsoft.com/en-us/library/z883w3dc.aspx –

3

istediğini yapacağını bir Linq deyim - ben şahsen iç içe foreach ile sopa bakarak olsa döngüler - çok daha kolay okunur:

var columnList= new List<List<double>>(); 
columnList.Add(new List<double>() { 1, 2, 3 }); 
columnList.Add(new List<double>() { 4, 5, 6 }); 
columnList.Add(new List<double>() { 7, 8, 9 }); 
columnList.Add(new List<double>() { 10, 11, 12 }); 

int columnCount = columnList[0].Count; 
var rowList = columnList.SelectMany(x => x) 
         .Select((x, i) => new { V = x, Index = i }) 
         .GroupBy(x => (x.Index + 1) % columnCount) 
         .Select(g => g.Select(x=> x.V).ToList()) 
         .ToList(); 

Bu örnek, yalnızca sabit sütun sayısı olan bir matris üzerinde de çalışır. Temel olarak matrisin bir listeye düzleştirilmesi, daha sonra satırların listesi oluşturularak listedeki elemanın indeksine göre gruplanarak sütun sayısı oluşturulur.

Düzenleme:

yükü yanında çok iç içe bir döngü daha yakın ve muhtemelen benzer performans farklı bir yaklaşımı.

int columnCount = columnList[0].Count; 
int rowCount = columnList.Count; 

var rowList = Enumerable.Range(0, columnCount) 
         .Select(x => Enumerable.Range(0, rowCount) 
               .Select(y => columnList[y][x]) 
               .ToList()) 
         .ToList(); 
+0

+1 - Bu, sabit sütun sayısıyla ilgili notunuz iyi – Seth

+0

Hmm okunabilirliği muhtemelen daha az dostudur. Sürüm, sürüm ve Linq ifadesi arasında aynı mı olurdu? – Seth

+0

@Seth: Sürümünüzün * daha kötüsü olduğunu * varsayalım, çünkü daha sonra yeniden gruplandırmak zorundayken, döngü, liste öğesinin dizinini kullanarak satır listelerini doğrudan oluşturmak için – BrokenGlass

2
var inverted = Enumerable.Range(0, columnCount) 
       .Select(index => columnList.Select(list => list[index])); 

Kısacası, biz bir aralığındaki sütun indeksi numaralandırmak ve her listenin n'inci elemanını toplamak için kullanabilirsiniz.

Lütfen her listenin aynı sayıda sütuna sahip olduğunu kontrol etmeniz gerektiğini unutmayın.

0

Dikdörtgen (düzensiz) matrisler için çalışan bir tane. Buradaki C# kodu, ücretsiz, etkileşimli bir C# programlama aracı olan LinqPad'u keserek yapıştırın.

Bir postfix işlecini (yani, bir uzantı yöntemi) tanımlarım. "Transpose."

var rand = new Random(); 

    var xss = new [] { 
     new [] {rand.NextDouble(), rand.NextDouble()}, 
     new [] {rand.NextDouble(), rand.NextDouble()}, 
     new [] {rand.NextDouble(), rand.NextDouble()}, 
    }; 

    xss.Dump("Original"); 
    xss.Transpose().Dump("Transpose"); 

böyle bir şey sonuçlanan: şu şekildedir: operatörünü kullanın

Original 
0.843094345109116 
0.981432441613373 

0.649207864724662 
0.00594645645746331 

0.378864820291691 
0.336915332515219 


Transpose 
0.843094345109116 
0.649207864724662 
0.378864820291691 

0.981432441613373 
0.00594645645746331 
0.336915332515219 

bu operatör uygulanması özü İşte tam uygulamasıdır

public static IEnumerable<IEnumerable<T>> Transpose<T>(this IEnumerable<IEnumerable<T>> xss) 
    { 
     var heads = xss.Heads(); 
     var tails = xss.Tails(); 

     var empt = new List<IEnumerable<T>>(); 
     if (heads.IsEmpty()) 
      return empt; 
     empt.Add(heads); 
     return empt.Concat(tails.Transpose()); 
    } 

takip ediyor, Bazı çizgilerle, fonksiyonun nasıl çalıştığını izleyemediğinizi belirtebilirsiniz. Arka arkaya, iç (ikinci) birinci indeks ve sütun belirtir:

void Main() 
{ 
    var rand = new Random(); 

    var xss = new [] { 
     new [] {rand.NextDouble(), rand.NextDouble()}, 
     new [] {rand.NextDouble(), rand.NextDouble()}, 
     new [] {rand.NextDouble(), rand.NextDouble()}, 
    }; 
    xss.Dump("Original"); 
    xss.Transpose().Dump("Transpose"); 
} 

public static class Extensions 
{ 
    public static IEnumerable<T> Heads<T>(this IEnumerable<IEnumerable<T>> xss) 
    { 
     Debug.Assert(xss != null); 
     if (xss.Any(xs => xs.IsEmpty())) 
      return new List<T>(); 
     return xss.Select(xs => xs.First()); 
    } 

    public static bool IsEmpty<T>(this IEnumerable<T> xs) 
    { 
     return xs.Count() == 0; 
    } 

    public static IEnumerable<IEnumerable<T>> Tails<T>(this IEnumerable<IEnumerable<T>> xss) 
    { 
     return xss.Select(xs => xs.Skip(1)); 
    } 

    public static IEnumerable<IEnumerable<T>> Transpose<T>(this IEnumerable<IEnumerable<T>> xss) 
    { 
//  xss.Dump("xss in Transpose"); 
     var heads = xss.Heads() 
//   .Dump("heads in Transpose") 
      ; 
     var tails = xss.Tails() 
//   .Dump("tails in Transpose") 
      ; 

     var empt = new List<IEnumerable<T>>(); 
     if (heads.IsEmpty()) 
      return empt; 
     empt.Add(heads); 
     return empt.Concat(tails.Transpose()) 
//   .Dump("empt") 
      ; 
    } 
} 
1

bazen ters bir şekilde orijinal cevap sütunlar ve satırlar ya da için kullanılan gelenekselden, yukarıda bazı yanıtlar birleştirerek am indeks. Örneğin. değerleri [satır] [sütun]

public static List<List<T>> Transpose<T>(this List<List<T>> values) 
    { 
     if (values.Count == 0 || values[0].Count == 0) 
     { 
      return new List<List<T>>(); 
     } 

     int ColumnCount = values[0].Count; 

     var listByColumns = new List<List<T>>(); 
     foreach (int columnIndex in Enumerable.Range(0, ColumnCount)) 
     { 
      List<T> valuesByColumn = values.Select(value => value[columnIndex]).ToList(); 
      listByColumns.Add(valuesByColumn); 
     } 
     return listByColumns; 
    }    

Aslında kelime satır ve sütun satırlar ve sütunlar halinde veri düşünmenin sadece bizim kongre ve bazen onları çözme çok belirsizlik ekler.

Aslında dış dizinin iç dizinini değiştiriyoruz. (veya dizinleri ters çevirerek). Yani, sadece aşağıdaki uzantı yöntemini de tanımlayabiliriz. . Yine, yukarıdaki çözümlerden ödünç aldım, onu sadece okunabilir ve oldukça kompakt bulduğum bir şeye koydum.

İç listelerin eşit büyüklükte olduğunu kontrol eder.

public static List<List<T>> InsideOutFlip<T>(this List<List<T>> values) 
    { 
     if (values.Count == 0 || values[0].Count == 0) 
     { 
      return new List<List<T>>(); 
     } 

     int innerCount = values[0].Count; 

     var flippedList = new List<List<T>>(); 
     foreach (int innerIndex in Enumerable.Range(0, innerCount)) 
     { 
      List<T> valuesByOneInner = values.Select(value => value[innerIndex]).ToList(); 
      flippedList.Add(valuesByOneInner); 
     } 
     return flippedList; 
    }