IEnumerable与Prev / Next

时间:2012-10-07 17:16:42

标签: c# linq

只是在寻找一些确认。我需要捕获列表的上一个和下一个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();

2 个答案:

答案 0 :(得分: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();

答案 1 :(得分: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;

这保留了一些&#34;精神&#34;函数式编程,但您也可以简单地使用闭包并在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 ();