2016-06-01 22 views
2

"Text1"、 "Text2"、新しいUndefinedInfo( "Undfined1")、新しいUndefinedInfo( "Undfined2")、新しいUndefinedInfo( "Undefined3")のリストがあります。 、 "テキスト3"分割オブジェクトタイプに基づくオブジェクトのリスト

は、私は以下のように出力を必要とする:

出力 //一覧> 0 - テキスト1、テキスト2 1 - Undefined1、Undefined2、Undefined3 2 - テキスト3

私が書くために管理しました下の機能は悪いですが、何とかうまく機能しています。 TakeWhileやSkipWhileなどのLINQ拡張機能を使用するか、yieldを使用して同じことを達成する方法はありますか?すべてのヘルプ高く評価:

public static List<List<object>> PartitionByTypes(List<object> values) 
{ 
List<List<object>> partitionedList = new List<List<object>>(); 

     int j; 
     for (int i = 0; i < values.Count; i++) 
     { 
      j = i; 
      List<object> subList = new List<object>(); 
      Type t = values[j].GetType(); 
      do 
      { 
       subList.Add(values[j]); 
       j++; 
       if (j == values.Count) 
       { 
        break; 
       } 
      } while (values[j].GetType() == t); 
      partitionedList.Add(subList); 
      i = j - 1; 
     } 

     return partitionedList; 
    } 
+1

はこれを試してみてください())。ToArray()); – jdweng

+0

私は最後にpartitionedListを埋めています。あなたのソリューションはどのように機能しますか?サンプルの入力と出力を提供できますか? – Abhay

+0

あなたの出力はCSV文字列です(各配列項目はコンマで区切られています)。私のコードは、各項目を文字列に変換し、文字列JOINメソッドを使用して各項目間にコンマを入れてリストを列挙しています。 partitionListの代わりに値を使うべきです。 – jdweng

答えて

0

さてあなたは、LINQとTakeWhileでこれを行うことができますが、私はそれが普通のforeachよりも良くなることはないだろう。たとえば:

public static List<List<object>> LinqPartitionByTypes(List<object> values) 
{ 
    var batches = new List<List<object>>(); 
    while (true) 
    { 
     object prev = null; 
     var batch = values.Skip(batches.Sum(c => c.Count)).TakeWhile(c => { 
       var result = prev == null || prev.GetType() == c.GetType(); 
       prev = c; 
       return result; 
     }).ToList(); 
     if (batch.Count == 0) 
       break; 
     batches.Add(batch); 
    } 
    return batches; 
} 

は、しかし、私はよりシンプルでクリーンな何かをよりよくしたい:

public static List<List<object>> PartitionByTypes(List<object> values) { 
    var batches = new List<List<object>>(); 
    object prev = null; 
    var batch = new List<object>(); 
    foreach (var value in values) { 
     if (prev != null && prev.GetType() != value.GetType()) { 
      batches.Add(batch); 
      batch = new List<object>(); 
     } 
     batch.Add(value); 
     prev = value; 
    } 
    if (batch.Count > 0) 
     batches.Add(batch); 

    return batches; 
} 
+0

リストがタイプによってソートされていない限り、同じタイプのすべてのインスタンスを1つのバッチにグループ化することはできません。 –

+0

私はそれがすべての点であることを理解しています - 同じタイプのすべての連続するオブジェクトを別々のグループに分割します。 – Evk

+0

あなたの最初の方法で 'バッチを返す 'ことを忘れました。 – juharr

2

以下は、あなたがyieldを使用してやりたいだろう。返品はIEnumerable<List<object>>になります。

public static IEnumerable<List<object>> PartitionByTypes(List<object> values) 
{ 
    Type prevType = null; 
    List<object> cache = new List<object>(); 
    foreach (var value in values) 
    { 
     if(prevType != null && value.GetType() != prevType) 
     { 
      yield return cache; 
      cache = new List<object>(); 
     } 

     cache.Add(value); 
     prevType = value.GetType(); 
    } 

    if(cache.Count > 0) 
     yield return cache; 
} 

は、別の方法としては、以下のLINQクエリを使用することができ

public static IEnumerable<List<object>> PartitionByTypes(List<object> values) 
{ 
    int count = 0; 
    return values.Select((o, i) => new 
     { 
      Object = o, 
      Group = (i == 0 || o.GetType() == values[i - 1].GetType()) ? count : ++count 
     }) 
     .GroupBy(x => x.Group) 
     .Select(g => g.Select(x => x.Object).ToList()); 
} 
+0

これは入力リストの最後の要素をスキップします。すなわち、2つのリストのリストを返します。 – Abhay

+0

@Abhay最後に 'if(cache.Count> 0)yield return cache;で修正しました。 – juharr

+0

@juharr ... perfect ... :)ソリューションのおかげで – Abhay

0
static Type GetObjectTypeOrNull(object o) 
{ 
    return o == null ? null : o.GetType(); 
} 

static IEnumerable<List<object>> PartitionByTypes(List<object> values) 
{ 
    if (values == null) throw new ArgumentNullException("values"); 
    if (values.Count == 0) yield break; 

    Type currentType = GetObjectTypeOrNull(values); 
    List<object> buffer = new List<object>(); 
    foreach (object value in values) 
    { 
     Type valueType = GetObjectTypeOrNull(value); 
     if (valueType != currentType) 
     { 
      currentType = valueType; 
      yield return buffer; 
      buffer = new List<object>(); 
     } 

     currentType = valueType; 
     buffer.Add(value); 
    } 

    if (buffer.Count > 0) 
    { 
     yield return buffer; 
    } 
} 

例:

List<object> input = new List<object> { "Text1", "Text2", new UndefinedInfo("Undefined1"), new UndefinedInfo("Undefined2"), new UndefinedInfo("Undefined3"), "Text3" }; 
PartitionByTypes(input).ToList(); 

結果:

{ List<object>(2) { "Text1", "Text2" }, List<object>(3) { [Undefined1], [Undefined2], [Undefined3] }, List<object>(1) { "Text3" } 

別の例 - NULL値を持つ:

List<object> input = new List<object> { null, "Text1", "Text2", null, null, new UndefinedInfo("Undefined1"), null, null, new UndefinedInfo("Undefined2"), new UndefinedInfo("Undefined3"), "Text3" }; 
PartitionByTypes(input).ToList(); 

結果:文字列出力= string.Join( ""、partitionedList.Select(X => x.ToString:

List<object>(1) { null }, List<object>(2) { "Text1", "Text2" }, List<object>(2) { null, null }, List<object>(1) { [Undefined1] }, List<object>(2) { null, null }, List<object>(2) { [Undefined2], [Undefined3] }, List<object>(1) { "Text3" } 
+0

ありがとう@ alex.b nullの例 – Abhay

関連する問題