2017-11-28 21 views
0

コンテキスト:LINQ First/FirstOrDefaultは列挙可能な全体を反復処理しますか?

私はタイプIEnumerable<int>の変数numbersを持っています。
数字が昇順であるかどうかをチェックしたいと思います。

アルゴリズムは、だから私はprevに格納する最初の要素を取得し、その次以降の数字に対してチェックしたかったです。

// numbers can contain "10, 20, 60, 50" 
IEnumerable<int> numbers = TraverseInOrder(root); 
int prev = numbers.FirstOrDefault(); 
foreach (var curr in numbers.Skip(1)) 
{ 
    if (curr < prev) return false; 
    prev = curr; 
} 
return true; 

質問 Iはnumbers.FirstOrDefault()を用いprevの値を設定し、また、次の要素から開始するforeachに一つの要素(numbers.Skip(1))をスキップしています。以下のコードのための

ので、

numbers.FirstOrDefault() 
numbers.Skip(1) 

私はnumbersを列挙アム二回O(2N)?意味FirstOrDefault全体のリストを繰り返しますか?
- または -
まだO(N)ですか? (FirstOrDefaultのO(1)一定時間はSkip(1)のO(N))

+5

ソースコードを見てください。https://referencesource.microsoft.com/#System.Core/System/Linq/Enumerable.cs,1033 – Nkosi

+7

@Sung正しいですが、SOには多くの悪い質問があります彼らはドキュメントを読むことによって簡単に答えられているので、尋ねられてはならないはずです。それは、ドキュメントを読むことで簡単に答えられる質問をするのは大丈夫だということではありません。あなたがドキュメントの答えを調べたり、自分のコードを実行したり、それが何をしているのかわからないので、SOは質問をする場所ではありません。 – Servy

+0

または単に 'int prev = int.MinValue' – Slai

答えて

6

ビット微妙である。

Enumerable.FirstOrDefaultは、それを行うことに意味がないので、全体のシーケンスを列挙しません。ここthe implementationです:

public static TSource FirstOrDefault<TSource>(this IEnumerable<TSource> source) { 
    if (source == null) throw Error.ArgumentNull("source"); 
    IList<TSource> list = source as IList<TSource>; 
    if (list != null) { 
     if (list.Count > 0) return list[0]; 
    } 
    else { 
     using (IEnumerator<TSource> e = source.GetEnumerator()) { 
      if (e.MoveNext()) return e.Current; 
     } 
    } 
    return default(TSource); 
} 

配下のシーケンスがIList<T>であるが、それ以外列挙がを開始されている場合は、最適化されたバージョンを取得します。

今、あなたのIEnumerable<T>が実際にデータベースクエリを表しEntity FrameworkのIQueryable<T>で想像してみてください。これはつまり、あなたのコードが依然としての2度のというクエリを実行するということです。

IEnumerable<T>シーケンスを経験則として複数回列挙することを避ける方が良いでしょう。シーケンスの列挙が安価であることが分かっている場合は、ICollection<T>またはIReadOnlyCollection<T>のような、よりわかりやすいタイプを使用する必要があります。

+0

私は' source.GetEnumerator() 'のソースも読みました https://github.com/Microsoft/referencesource/blob/master/mscorlib/system/collections/ generic/list.cs#L1140 「列挙が開始されます」、「FirstOrDefault」は最初の要素にしか届かないように見えます。 答えが – Sung

+1

@Sungはい。ありがとうございます。しかし、データベースクエリの例では、最初の行のみを取得しますが、クエリはその行に到達するために実行されます。 –

0

FirstOrDefault()全体のコレクションを繰り返すわけではありません。

IEnumerable and order

ちょうど行います

var moreNumbers = numbers.ToList(); 
// ...stuff with the list. 
2
(他の回答は、あなたが特別に求めてきました何対処が)あなたが知っておく必要がないように、私は微妙にあなたのテクニックを変更します

IEnumerable<int> numbers = TraverseInOrder(root); 
int prev = 0; 
bool first = true; 
foreach (var curr in numbers) 
{ 
    if (!first && curr < prev) return false; 
    prev = curr; 
    first = false; 
} 
return true; 

このコードでは、一度だけenumerableを繰り返し処理することがわかりました(ドキュメントを読んでいなくても)。

+0

大きなアドバイスありがとうございます@Damien_The_Unbeliever – Sung

関連する問題