2017-08-13 6 views
2

私はこの(簡体字)の例と同様、コレクション、構築するために流れるようなインターフェイスを使用するようにしようとしている:流暢なインターフェースを使ってシーケンスを構築するには?

var a = StartWith(1).Add(2).Add(3).Add(4).ToArray(); 
    /* a = int[] {1,2,3,4}; */ 

として、私は追加の追加(を考え出すことができる最適なソリューション):

IEnumerable<T> Add<T>(this IEnumerable<T> coll, T item) 
    { 
    foreach(var t in coll) yield return t; 
    yield return item; 
    } 

各呼び出しで繰り返されるオーバーヘッドが増えるようです。

良い方法がありますか?

更新: 私の急いで、私は例を過度に単純化し、重要な要件を省いた。既存のcollの最後の項目は次の項目に影響します。だから、わずかに少ない簡単な例:私はパフォーマンスの高い方法で、リストにインデックスすることを可能にしてあることをIReadOnlyListを使用してい

public static class MySequenceExtensions 
{ 
    public static IReadOnlyList<int> Times10Plus(
     this IReadOnlyList<int> sequence, 
     int value) => Add(sequence, 
          value, 
          v => sequence[sequence.Count - 1] * 10 + v); 

    public static IReadOnlyList<T> Starts<T>(this T first) 
     => new MySequence<T>(first); 

    public static IReadOnlyList<T> Add<T>(
     this IReadOnlyList<T> sequence, 
     T item, 
     Func<T, T> func) 
    { 
     var mySequence = sequence as MySequence<T> ?? 
         new MySequence<T>(sequence); 
     return mySequence.AddItem(item, func); 
    } 

    private class MySequence<T>: IReadOnlyList<T> 
    { 
     private readonly List<T> innerList; 

     public MySequence(T item) 
     { 
      innerList = new List<T>(); 
      innerList.Add(item); 
     } 

     public MySequence(IEnumerable<T> items) 
     { 
      innerList = new List<T>(items); 
     } 

     public T this[int index] => innerList[index]; 
     public int Count => innerList.Count; 

     public MySequence<T> AddItem(T item, Func<T, T> func) 
     { 
      Debug.Assert(innerList.Count > 0); 
      innerList.Add(func(item)); 
      return this; 
     } 

     public IEnumerator<T> GetEnumerator() => innerList.GetEnumerator(); 
     IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); 
    } 
} 

注:

var a = StartWith(1).Times10Plus(2).Times10Plus(3).Times10Plus(4).ToArray(); 
    /* a = int[] {1,12,123,1234}; */ 

public static IEnumerable<T> StartWith<T>(T x) 
{ 
    yield return x; 
} 

static public IEnumerable<int> Times10Plus(this IEnumerable<int> coll, int item) 
{ 
    int last = 0; 
    foreach (var t in coll) 
    { 
     last = t; 
     yield return t; 
    } 
    yield return last * 10 + item; 
} 
+0

興味深い質問です。しかし、私はこれをうまくやるためのより良い方法があるかどうかはわかりません。あなたは 'Add'メソッドを' params'配列にしてそれらをすべて一度に追加することができますが、それは本当に質問に答えるものではありません。 – DavidG

+0

私はそこにいるとは思わない。たとえば、 'ImmutableList 'などのような内部バッファリングをしている場合を除きます。 –

答えて

1

次の操作を行うことができます必要に応じて最後の要素を取得することができます。あなたが怠惰な列挙を必要とするなら、私はあなたがあなたの元のアイデアに悩まされていると思います。

そして次、十分に確認してください。

var a = 1.Starts().Times10Plus(2).Times10Plus(3).Times10Plus(4).ToArray(); 

は、期待される結果({1, 12, 123, 1234})私は、合理的なパフォーマンスと思われるもの、とを生成します。

+0

これらのメソッド呼び出しはすべて、単純にすべてが単一の変更可能(および変更された)データ構造に同じ参照を返すだけです。だから 'var start = Starts(1); var nextValue = start.Times10Plus(2); Console.WriteLine(start.Count); 'それは1ではなく2を出力しますが、これは間違っています。 – Servy

+0

@servyはい私は知っていますが、これが望ましくないかどうかという疑問からは明らかではありません。とにかく簡単に修正可能ですが、インナータイプとして不変のキューを使用するだけです。列挙がパフォーマンス上重要でない場合、逆の順序で列挙する単純で直接的で不変なスタックを使用することもできます。 – InBetween

+0

つまり、OPのソリューションを使用して戻ってきました。 – Servy