2011-08-05 11 views
10

क्या कोई फैंसी LINQ अभिव्यक्ति है जो मुझे अधिक सरल फैशन में निम्नलिखित करने की अनुमति दे सकती है। मेरे पास List<List<double>> है, यह मानते हुए कि सूची 2 डी मैट्रिक्स में कॉलम हैं, मैं स्तंभों की सूची पंक्तियों की सूची में स्वैप करना चाहता हूं। मैं निम्नलिखित स्पष्ट समाधान है:LINQ स्वैप कॉलम पंक्तियों में

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

उत्तर

5

आप बहुत आसानी से भीतरी पाश LINQify सकता है:

vector.AddRange(values.Select(value => value[i]));

हो या न हो कि पठनीयता में सुधार आप पर निर्भर करता छोड़ दिया है!

+0

@ डीबीएम: परिभाषा क्या है AddRange का? –

+0

@ रीब। केबिन: http://msdn.microsoft.com/en-us/library/z883w3dc.aspx –

3

यहाँ एक Linq अभिव्यक्ति है कि आप क्या चाहते हैं क्या करना होगा है - इसे देख मैं व्यक्तिगत रूप से नेस्टेड foreach के साथ चिपके रहते हैं चाहते हैं, हालांकि लूप - बहुत आसान को पढ़ने के लिए:

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

यह उदाहरण केवल एक निश्चित कॉलम गिनती के साथ एक मैट्रिक्स पर काम करेगा। असल में यह मैट्रिक्स को एक सूची में फटकार रहा है, फिर सूची मॉड्यूल में कॉलम गिनती में तत्व के सूचकांक द्वारा समूहित करके पंक्तियों की सूची बना रहा है।

संपादित करें:

एक अलग दृष्टिकोण, ज्यादा भूमि के ऊपर के अलावा एक नेस्टेड लूप के करीब है और शायद इसी तरह के प्रदर्शन।

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 - कि तय स्तंभ संख्या – Seth

+0

हम्म पठनीयता के बारे में अपनी टिप्पणी को फिर से ठीक है शायद कम अनुकूल है। क्या प्रदर्शन मेरे संस्करण और लिंक अभिव्यक्ति के बीच समान होगा? – Seth

+0

@ सेठ: मुझे लगता है कि यह आपके संस्करण की तुलना में * बदतर * करता है, क्योंकि इसे फिर से समूह करना पड़ता है, जबकि लूप सूची सूची के सूचकांक का उपयोग सीधे पंक्ति सूची बनाने के लिए करता है – BrokenGlass

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

संक्षेप में, हम एक सीमा से स्तंभ अनुक्रमणिका गणना और प्रत्येक सूची के n वें तत्व इकट्ठा करने के लिए इसका इस्तेमाल करते हैं।

कृपया ध्यान दें कि आपको यह जांचने की आवश्यकता होगी कि प्रत्येक सूची में कॉलम की संख्या समान है।

0

यहां एक ऐसा है जो आयताकार (गैर-रैग किए गए) मैट्रिस के लिए काम करता है। सी # कोड यहां एक मुक्त, इंटरैक्टिव सी # प्रोग्रामिंग टूल, LinqPad में कट-एंड-पेस्ट काम करता है।

मैं एक पोस्टफिक्स ऑपरेटर (यानी, एक विस्तार विधि) परिभाषित करता हूं "ट्रांसपोज़ करें।"

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

कुछ इस तरह है, जिसके परिणामस्वरूप: इस प्रकार ऑपरेटर का प्रयोग करें

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 

इस ऑपरेटर के कार्यान्वयन का सार पीछा कर रहा है

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

यहाँ पूर्ण कार्यान्वयन है, कुछ पंक्तियों के साथ टिप्पणी की गई कि आप काम करने के लिए असुविधा कर सकते हैं कि फ़ंक्शन कैसे काम करता है।

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

मैं ऊपर कुछ उत्तर के संयोजन कर रहा हूँ, जो कभी कभी स्तंभों और पंक्तियों उल्टे रूप मूल जवाब था या सम्मेलन मैं करने के लिए इस्तेमाल कर रहा हूँ से: पंक्ति पहले सूचकांक और आंतरिक (दूसरा) स्तंभ को संदर्भित करता है सूचकांक। जैसे मूल्यों [पंक्ति] [स्तंभ]

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

असल शब्द पंक्ति और स्तंभ सिर्फ पंक्तियों और स्तंभों में डेटा के बारे में सोच के बारे में हमारी परंपरा है, और कभी कभी उन्हें सुलझाने की तुलना में अधिक भ्रम की स्थिति कहते हैं।

हम वास्तव में बाहरी सूचकांक के लिए आंतरिक सूचकांक को स्वैप कर रहे हैं। (या आसपास इंडेक्स flipping)। तो कोई भी निम्नलिखित विस्तार विधि को परिभाषित कर सकता है। । फिर मैंने उपर्युक्त समाधानों से उधार लिया, बस इसे उस चीज़ में डाल दिया जो मुझे पठनीय और काफी कॉम्पैक्ट लगता है।

चेक करता है कि आंतरिक सूचियां बराबर आकार के हैं।

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; 
    }    
संबंधित मुद्दे