これから始めます:
IEnumerable<KeyValuePair<int, double>> ReadFrames(string path)
{
return File.ReadLines(path).Select(l =>
{
var parts = l.Split(' ').Select(p => p.Trim());
return new KeyValuePair<int, double>(
int.Parse(parts.First()),
double.Parse(parts.Skip(1).First()));
});
}
フレームができたので、位置番号でフレームを調べてみましょう。
int GetFrameByPosition(IEnumerable<KeyValuePair<int,double>> frames, double position)
{
return frames.SkipWhile(f => f.Value < position).First().Key;
}
ワンライナーであることに注意してください。次のように呼び出します。
int frameNumber = GetFrameByPosition(GetFrames("path"), 18.10D);
別の質問に答える必要がある場合、それもワンライナーになる可能性があります。たとえば、そのコードは入力よりも大きい最初のフレームを取得しますが、最も近いものを要求しました。これは、この前のフレームである可能性があります。次のように実行できます。
int GetNearestFrameByPosition(IEnumerable<KeyValuePair<int,double>> frames, double position)
{
return frames.OrderBy(f => Math.Abs(position - f.Value)).First().Key;
}
もう 1 つの例は、再生の開始位置をシークするためにこれを使用していて、その最初のフレームから始まるすべてのフレームが本当に必要な場合です。簡単です:
IEnumerable<KeyValuePair<int,double>> SeekToFrameByPosition(IEnumerable<KeyValuePair<int,double>> frames, double position)
{
return frames.SkipWhile(f => f.Value < frames.OrderBy(f => Math.Abs(position - f.Value)).First().Key);
}
まだワンライナーです。
ここでの唯一の弱点は、ファイルが毎回ディスクから読み取られるたびにファイルに戻ると、低速になることです。それはあなたが必要とするものかもしれませんが、それを行う必要がない場合は、次のようにすべてのフレームを前もってメモリにロードすることで、簡単に高速化できます。
var cachedFrames = ReadFrames("path").ToList();
次に、ReadFrames() 関数を再度呼び出す代わりに、その cachedFrames 変数をどこでも使用します。
最後に、カスタム クラスの作成を支持して KeyValuePair の使用を避ける考え方があります。そのクラスは次のようになります。
public class Frame
{
public int index {get;set;}
public double position {get;set;}
}
上記のどこでもそれを使用してくださいKeyValuePair<int,double>
。また、これは十分に小さい (< 16 バイト) ため、クラスではなく構造体と見なすことができます。構造体を使用する場合は、それをimmutableにすることもお勧めします。これは、コンストラクターでメンバーを設定し、後でそれらを決して変更しないという派手な方法です。
public struct Frame
{
public Frame(int index, double position)
{
this.index = index;
this.position = position;
}
public int index {get;private set;}
public double position {get;private set;}
}