2

我有以下 LINQ 语句:

IEnumerable<Statement> statement = bookmarkCollection.AsEnumerable().Select(
bookmark => new Statement()
{
    Title = bookmark.Title,
    PageNumber = bookmark.PageNumber
});

Statement 有另一个名为 NextPageNumber 的属性,我需要能够填充该属性。NextPageNumber 等于下一条记录的 PageNumber 减去 1。本质上是这样的:

IEnumerable<Statement> statement = bookmarkCollection.AsEnumerable().Select(
bookmark => new Statement()
{
    Title= bookmark.Title,
    PageNumber = bookmark.PageNumber,
    NextPageNumber = ???
});

更新:

我尝试了提供的一些解决方案,但我仍然使用 .NET 3.5,因此 Tuple 方法已失效。Zip 操作有效(我有模拟 Zip 3.5 的扩展方法),但它不会为最后一个书签创建语句。最后一个书签的 NextPageNumber 就是 PDF 中的页数。

最后更新:

非常感谢大家。在您的帮助下,我能够正常工作。

4

5 回答 5

4

这是一个辅助函数,它将一个序列映射为一个对序列,其中每一对是每个项目与它后面的项目配对。

public static IEnumerable<Tuple<T, T>> WithNext<T>(this IEnumerable<T> source)
{
    using (var iterator = source.GetEnumerator())
    {
        if(!iterator.MoveNext())
            yield break;

        T previous = iterator.Current;
        while (iterator.MoveNext())
        {
            yield return Tuple.Create(previous, iterator.Current);
            previous = iterator.Current;
        }

        yield return Tuple.Create(previous, default(T));
    }
}

现在你可以这样做:

var query = bookmarkCollection.AsEnumerable()
.WithNext()
.Select(pair => new Statement(){
    Title= pair.Item1.Title,
    PageNumber = pair.Item1.PageNumber,
    NextPageNumber = pair.Item2.PageNumber - 1, //note you'll need to null check for the last item
});
于 2013-05-22T20:13:02.473 回答
2
var bc = bookmarkCollection.AsEnumerable();
IEnumerable<Statement> statement = bc.Zip(bc.Skip(1), 
    (b1,b2) => new Statement()
    {
        Title= b1.Title,
        PageNumber = b1.PageNumber,
        NextPageNumber = b2.PageNumber - 1
    });

编辑:(根据下面的评论):如果您还需要包含最后一项,那么您最好使用@Servy 的辅助方法。

你可以这样做...

var bc = bookmarkCollection.AsEnumerable();
IEnumerable<Statement> statement = bc.Zip(bc.Skip(1).Concat(new Bookmark[] { null }), 
    (b1,b2) => new Statement()
    {
        Title= b1.Title,
        PageNumber = b1.PageNumber,
        NextPageNumber = b2 == null ? 0 : b2.PageNumber - 1
    });

...但是,我最初建议Zip只是因为它既快速又简单——现在它变得有点难以解释了。因此,我建议您使用 @Servy 的方法稍作修改以包含选择器功能:

public static IEnumerable<TResult> WithNext<T, TResult>(this IEnumerable<T> source, Func<T, T, TResult> selector)
{
    using (var e = source.GetEnumerator())
    {
        if (!e.MoveNext()) yield break;

        T previous = e.Current;
        while (e.MoveNext())
        {
            yield return selector(previous, e.Current);
            previous = e.Current;
        }

        yield return selector(previous, default(T));
    }
}

并像这样使用它:

IEnumerable<Statement> statement = bc.WithNext(
   (b1, b2) => new Statement()
   {
       Title = b1.Title,
       PageNumber = b1.PageNumber,
       NextPageNumber = b2 == null ? 0 : b2.PageNumber - 1
   }).ToList();
于 2013-05-22T20:19:08.377 回答
2

.Zip使用 for 循环可能会更好,但如果你真的在 linq 上设置,你可以使用它来拼凑一些东西:

var strings = new[] { "one", "two", "three", "four", "five" };

var result = strings.Zip(
    strings.Skip(1).Concat(Enumerable.Repeat("last", 1)), 
    (a, b) => new { a, b }
);

结果

one   two 
two   three 
three four 
four  five 
five  last 
于 2013-05-22T20:11:31.537 回答
0

您可以尝试使用 Linq 解决此问题,尝试索引选择,如下所示:

var statement = bookmarkCollection.AsEnumerable().Select(
    (bookmark, index) => new Statement()
{
    Title = bookmark.Title,
    PageNumber = bookmark.PageNumber,
    NextPageNumber = index < bookmarkCollection.Count -1 ? bookmarkCollection[index + 1].PageNumber - 1 : -1
});

上面的代码在没有下一条记录时将 NextPageNumber 设置为 -1。

Linq 的一个很好的参考是 1 01 LINQ Samples,您可以在其中看到其他索引选择示例:http ://code.msdn.microsoft.com/101-LINQ-Samples-3fb9811b

于 2013-05-22T20:17:22.290 回答
0

LINQ 没有提供一种简单的方法来做到这一点,没有使用ToList()or捕获结果ToArray()并迭代列表以更新每个连续的记录,例如:

var statements = bookmarkCollection.AsEnumerable().Select(
    bookmark => new Statement()
    {
        Title= bookmark.Title,
        PageNumber = bookmark.PageNumber,
    }).ToList();

for (var i = 0; i < statements.Length - 1; i++)
    statements[i].NextPageNumber = statements[i+1].PageNumber - 1;

从理论上讲,您也可以使用Select()需要 a 的重载Func<T, int, R>,但机制是相同的。

于 2013-05-22T20:11:54.827 回答