【问题标题】:Can I get the delta of two IEnumerables in LINQ?我可以在 LINQ 中获得两个 IEnumerable 的增量吗?
【发布时间】:2010-03-02 23:54:45
【问题描述】:

不是聚合增量,而是每个元素的增量。这是一些代码来解释我的意思:

var deltaTotals = _deltaEnumerable.Select(a => a.Amount).ToList();
var oldTotals = _totalsEnumerable.Select(d => d.Amount).ToList();

// trigger change in _totalsEnumerable

// ** can LINQ do the lines below 
var newTotals = totalsEnumerable.Select(d => d.Amount);
for (var i = 0; i < 7; i++) {
    var newAmount = oldTotals[i] - deltaTotals[i];
    Assert.That(newTotals.ElementAt(i), Is.EqualTo(newAmount));
}

最后四行代码似乎在 LINQ 中可能有更优雅的方法。

干杯,
浆果

【问题讨论】:

    标签: c# linq


    【解决方案1】:

    您想要的是Enumerable.Zip 扩展方法。

    一个示例用法是:

    var delta = oldTotals.Zip(newTotals, (o, n) => n.Amount - o.Amount);
    

    请注意,这是 .NET 4.0 的新功能。在 .NET 3.5 中,您必须编写自己的扩展。像这样的:

    public static IEnumerable<TResult> Zip<TFirst, TSecond, TResult>(
        this IEnumerable<TFirst> first,
        IEnumerable<TSecond> second,
        Func<TFirst, TSecond, TResult> resultSelector)
    {
        using (var firstEnumerator = first.GetEnumerator())
        using (var secondEnumerator = second.GetEnumerator())
        {
            while ((firstEnumerator.MoveNext() && secondEnumerator.MoveNext()))
            {
                yield return resultSelector(firstEnumerator.Current,
                    secondEnumerator.Current);
            }
        }
    }
    

    【讨论】:

    • 酷。 Zip 对我来说似乎不是最有意透露名字的,但至少它很短。当我第一次看到你的答案时,我以为是下载!干杯
    • 没错,它不是世界上最容易被发现的名字。我认为 Eric Lippert 创造了这个词:blogs.msdn.com/ericlippert/archive/2009/05/07/zip-me-up.aspx。无论哪种方式,它都是一个有用的扩展。 :)
    • 这个名字来源于函数式语言。之所以这样称呼它,是因为它的工作原理类似于拉链。默认情况下,它应该执行类似于表单元组的操作,其中第一个元素来自列表 1,第二个来自列表 2。
    【解决方案2】:

    正如 Aaronaught 在他的回答中所说,您应该使用 Zip 方法;但是,它在 .NET 3.5 中不可用,仅在 4.0 中可用。这是一个自定义实现:

        public static IEnumerable<TResult> Zip<TFirst, TSecond, TResult>(this IEnumerable<TFirst> first, IEnumerable<TSecond> second, Func<TFirst, TSecond, TResult> selector)
        {
            if (first == null)
                throw new ArgumentNullException("first");
            if (second == null)
                throw new ArgumentNullException("second");
            if (selector == null)
                throw new ArgumentNullException("selector");
    
            return first.ZipIterator(second, selector);
        }
    
        private static IEnumerable<TResult> ZipIterator<TFirst, TSecond, TResult>(this IEnumerable<TFirst> first, IEnumerable<TSecond> second, Func<TFirst, TSecond, TResult> selector)
        {
            using (var enum1 = first.GetEnumerator())
            using (var enum2 = second.GetEnumerator())
            {
                while (enum1.MoveNext() && enum2.MoveNext())
                {
                    yield return selector(enum1.Current, enum2.Current);
                }
            }
        }
    

    【讨论】:

    • 甜蜜。 4.0 中是否有更多类似 Zip 的扩展?
    • Zip 是 Enumerable 类中唯一的新方法,但在某个地方可能还有其他方法......
    【解决方案3】:

    post 是相关的并提供answer

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-08-23
      • 1970-01-01
      • 2022-01-20
      • 2011-12-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-04-21
      相关资源
      最近更新 更多