2017-02-17 10 views
0

私はList<T>から派生したコレクションクラスを持っており、そのコレクションのインスタンスにパッケージactionを実行する必要があります。コレクションを分割して部品にactionを実行したい)。アクションには型付きのシグネチャがあることに注意してください。これは、同じ型のコレクションを予期する、あらかじめ定義されたメソッドです。Cでコピーを作成せずにリストの一部を取得する方法

私は

target.addRange(source.getRange(start, packageSize); 

を知っているが、このために、私は新しいコレクションのインスタンスを必要とし、リストのエントリのコピーを作成しますので、それは私が欲しいものではありません。私はアクションがどのような方法でリストを操作しないであろうことを知っていますので、私はこれらが「唯一」の参照を知っている(リストエントリのコピーを作成しないように意図して

action(source.Reference(fromIndex, toIndex); 

ような何かをするpreferrたいですC#でこれを行う方法はありますか?

もちろん、範囲を取得する方法を知っているactionにメソッドを渡すことはできますが、アクションは自分の意図について知る必要はありません実行を部分に細分化します。

+0

フィードバックに感謝します。あなたがdownvoteを説明するなら、私は質問を書く次の時間にaccoutにあなたの批評を取ることができます。 – Thomas

+0

_これらは「唯一の」参考文献であることを知っています。これは心配しないでください。これらの参照を常にコピーし、必要のない問題は解決しないでください。 –

+0

@HenkHolterman入力いただきありがとうございます。私は、私が得た答えからの示唆を使って、これが違いを生むかどうかをチェックします。プログラムは、一般的なPCではなく、限られたリソース(CPUの周波数とメモリ)を持つデバイス上で実行する必要があります。そのため、あらゆる種類のリソースで貪欲になるという習慣を開発しました。 – Thomas

答えて

1

Linqを使用してください:

var notAList = source.Skip(fromIndex).Take(toIndex-fromIndex); 
action(notAList); 

このようにして、列挙子を作成します。列挙子を使用すると、それらのすべてのためのスペースをインスタンス化せずに列挙できます。この演算子(SkipTakeが)実行を延期し、怠惰な評価を使用することを

public void MyAction<T>(IEnumerable<T> range) 
{ 
    // ... 
} 

と呼ん

MyAction(list.Skip(fromIndex).Take(toIndex-fromIndex)); 

注:

+0

'source.Take(toIndex).Skip(fromIndex)'を行う方が簡単でしょうか? – overactor

+0

@overactor私にはあなたの例は無効と思われます。 – eocron

+0

@overactorも動作します。しかし、 'Skip'はソースが' List 'であることを利用できないので少し遅くなりました。 –

1

あなたは、LINQのSkip()とそのためのTake()を使用することができます。だから、実際にはこれをソースリストの範囲の参照のようなものと考えることができます。

2

参照のコピーを新しいリストにする代わりに、LINQを使用するか、単純なC#を使用してリストから一部を取得することができます。

var iterator = source.Skip(start).Take(end - start); 

それはIEnumerableですので、あなたが呼び出されるメソッド内から(そう、あなたのメソッドのシグネチャを変更する必要があるかもしれません)というオーバーforeachすることができます:

foreach (var x in iterator) 
{ 
    ... 
} 
SkipTakeを使用して

または独自の状態マシンを作成してください。結果の列挙はあまりにメソッドに渡すことができます。

private static IEnumerable<T> Take<T>(List<T> source, int start, int end) 
{ 
    for (int i = start; i < end; i++) 
    { 
     yield return source[i]; 
    } 
} 
+0

返事をありがとうが、私はLinqステートメントの結果が異なるタイプの印象を受けています。 'action'は与えられた型を引数として期待します。 – Thomas

+0

あなたの 'Action'は何を期待していますか?私は 'IEnumerable 'を使うと、署名の変更が必要かもしれないと言いました。 –

+0

'List 'から派生したコレクションクラス – Thomas

1

あなたは自分のイテレータを作成することができます。そして、あなたはactionにイテレータのインスタンスを渡すことができ

public class MyPartListIterator: IEnumerator 
{ 
    private readonly IList list; 
    private readonly int _startIdx; 
    private readonly int _endIdx; 
    private int _current; 

    public MyIterator(IList list, int start, int end) 
    { 
     //do some validations before etc 
     this._startIdx = this._current = start; 
     this._endIdx = end; 
     this._list= list; 

    } 

    public bool MoveNext() 
    { 
     //do some checks against list was changed 

     if (this._current >= this._endIdx) return false; 
     this._current += 1; 
    } 

    public object Current => this._list[this._current]; 

    public void Reset() => this._current = this._startidx; 
} 

を。

なぜSkipTakeよりも優れていますか?インデックスを開始する前に要素を列挙しません。

もちろん、ジェネリック版を準備することもできます。

メモリから取得したもので、テストされていません。使用されたC#6.0構文の糖。

EDIT:

あなたの大きなILIst<T>IList<T>の同じ参照を渡すことはできません、それはソースリストの一部だけのデータが含まれています。

0

これは、拡張機能を使用して、探している機能を利用できる場所です。

public static class ListExtensions 
{ 
    public static void PerformActionOnSubset<T>(this IList<T> collection, int fromIndex, 
     int toIndex, Action<IList<T>> action) 
    { 
     action(collection.Skip(fromIndex).Take(toIndex - fromIndex).ToList()); 
    } 
} 

myCollectionOfSomethings.PerformActionOnSubset(10, 30, myAction); 
関連する問題