5

これについての確認を探しています。リストの前の ID と次の ID を取得する必要があります。より良い方法はありますか?

var questionArray = dc.Question
    .Where(i => !i.IsDeleted)
    .OrderBy(i => i.SortOrder)
    .Select(i => new
    {
        i.QuestionID,
        i.Name,
    })
    .ToArray();

var questionList = questionArray
    .Select((item, index) => new
    {
        item.QuestionID,
        PrevID = index > 0 ? questionArray[index - 1].QuestionID : (int?)null,
        NextID = index < questionArray.Length - 1 ? questionArray[index + 1].QuestionID : (int?)null,
        item.Name,
    })
    .ToList();
4

2 に答える 2

6

結果の配列を持つ必要性を取り除くために、小さなヘルパー拡張を書くことができます

public static IEnumerable<TResult> PrevNextZip<T, TResult>(this IEnumerable<T> stream, Func<T, T, T, TResult> selector) where T : class
{
  using (var enumerator = stream.GetEnumerator())
  { 
    if (enumerator.MoveNext())
    {
      T prev = null;
      T curr = enumerator.Current;

      while (enumerator.MoveNext())
      {
        var next = enumerator.Current;
        yield return selector(prev, curr, next);
        prev = curr;
        curr = next;
      }

      yield return selector(prev, curr, null);
    }
  }
} 

次に、結果を構築すると、次のようになります

  var questionList = questionArray.PrevNextZip((prev, item, next) => new
    {
      item.QuestionID,
      PrevID = prev != null ? prev.QuestionID : (int?)null,
      NextID = next != null ? next.QuestionID : (int?)null,
      item.Name,
    })
    .ToList();
于 2012-10-07T17:54:00.237 に答える
0

を使用してリストを作成できますAggregate。構築する集約は、次の要素に設定するための最後の要素を追跡し、新しい要素が挿入されるとすぐに最後の要素をPrevID更新します。NextIDこのようなことについて:

class Info { ... // QuestionID, PrevID, NextID, Name }
class ListBuilder { List<Info> list; Info lastElement; }

var questionList = dc.Question 
    .Where(i => !i.IsDeleted) 
    .OrderBy(i => i.SortOrder)
    .Aggregate (
        new ListBuilder () { list = new List<Info> (), lastElement = null },
        (acc, source) => {
            var lastElement = acc.lastElement;
            var newElement = new Info () {
                QuestionID = source.QuestionID,
                PrevID = lastElement != null ? lastElement.QuestionID : null,
                NextID = null
            };
            acc.list.Add (newElement);
            if (lastElement != null) lastElement.NextID = source.QuestionID;
            acc.lastElement = newElement;
            return acc;
         })
    .list;

これにより、関数型プログラミングの「精神」が保持されますが、単純にクロージャーを使用して、linq クエリの直前に定義されたローカル変数で必要な情報を追跡することもできます。

または、そのための関数を構築します。

IEnumerable<Info> previousNextInfo (IEnumerable<QuestionType> sourceEnumerable) {
   Info preprevious = null;
   Info previous = null;
   Info current = null;
   foreach (Info newOne in sourceEnumerable) {
      preprevious = previous;
      previous = current;
      current = newOne;
      yield return new Info () {
         QuestionID = previous.ID,
         lastID = preprevious != null ? preprevious.ID : null,
         nextID = current.ID
      };
   }
   if (current != null)
      yield return new Info () { QuestionID = current.ID, lastID = previous.ID, nextID = null };
}

...

questionList = previousNextInfo (dc.Question 
        .Where(i => !i.IsDeleted) 
        .OrderBy(i => i.SortOrder)
).ToList ();
于 2012-10-07T17:27:14.967 に答える