【问题标题】:IEnumerable items disappearing before being used using LINQ WhereIEnumerable 项目在使用 LINQ 之前消失在哪里
【发布时间】:2017-02-11 00:21:43
【问题描述】:

我对编程还很陌生,我一直在尝试编写一些随机函数。

我编写了下面的函数,它基于eratosthenes sieve 松散地工作。不过,最初,我在使用 updatedEntries IEnumerable 时遇到了问题。

updatedEntites 有点填充(与我收集的延迟执行有关 - 在调试模式下,“当前”为空,但结果视图包含相关项目)但是当 RemoveWhere 应用于oddPrimesAndMultiples 时,updatedEntries 中的项目消失了即使我不明白为什么它们仍应链接到oddPrimesAndMultiples 中的项目。 (当然,我可能完全误解了正在发生的事情,问题可能完全是另外一回事!)

如果我将 updatedEntries 更改为 List 而不是 IEnumerable 则不会出现问题,并且我现在实际上已经重写了该语句而不使用 LINQ 来(可能?)更好地利用我正在使用的事实 SortedSet 反正...但我仍然想知道为什么会出现这个问题!

这是我的代码:

public static IEnumerable<int> QuickPrimes()
        {
            int firstPrime = 2;
            int firstOddPrime = 3;

            int currentValue = firstOddPrime;
            int currentMinimumMultiple;

            SortedSet<Tuple<int, int>> oddPrimesAndMultiples = new SortedSet<Tuple<int, int>>() { new Tuple<int, int> (firstOddPrime, firstOddPrime) };
            IEnumerable<Tuple<int, int>> updatedEntries;

            yield return firstPrime;
            yield return firstOddPrime;

            while (true)
            {
                currentMinimumMultiple = oddPrimesAndMultiples.First().Item1;
                while (currentValue < currentMinimumMultiple)
                {
                    yield return currentValue;
                    oddPrimesAndMultiples.Add(new Tuple<int, int> (currentValue * 3, currentValue));
                    currentValue += 2;
                }

                updatedEntries = oddPrimesAndMultiples.Where(tuple => tuple.Item1 == currentMinimumMultiple)
                                                        .Select(t => new Tuple<int, int>(t.Item1 + 2 * t.Item2, t.Item2));

                oddPrimesAndMultiples.RemoveWhere(t => t.Item1 == currentMinimumMultiple);
                oddPrimesAndMultiples.UnionWith(updatedEntries);
                currentValue += 2;
            }
        }

以及我正在测试该功能的主要位置:

static void Main(string[] args)
        {
            foreach(int prime in Problems.QuickPrimes())
            {
                Console.WriteLine(prime);
                if (prime > 20) return;
            } 
        }

非常感谢!

【问题讨论】:

  • 一个 IEnumerable,使用 yield 关键字确实可以提供非常不同的结果。明智地使用它。
  • 让我看看我是否理解这一点,您的代码现在可以正常工作,但以前不是因为您没有对 updatedEntries 分配进行“.ToList()”调用,对吗?
  • 您能提供minimal reproducible example的问题吗?目前的帖子甚至不清楚代码是否存在您正在谈论的问题。
  • @Fredy Treboux 和 Alexei - 抱歉,updatedEntries 上的 .ToList() 不应该存在 - 我从更正的代码中粘贴代码时忘记删除它(我只是更改了updatedEntries 从 List 返回到 IEnumerable!)如果没有 ToList() 调用,则会发生 InvalidOperation 错误,因为正如我上面写的那样,这些项目已从 updatedEntries 中删除,然后这意味着oddPrimesAndMultiples 也是导致错误的条目,当我尝试首先调用它时!根据需要更新问题。
  • 请解释一个你观察到的基本例子,我觉得你的问题很难掌握。

标签: c# linq ienumerable


【解决方案1】:

陷阱是updatedEntries是在一行中定义的,但实际上是在执行之后。

要使其回归基础,请参阅以下代码 sn-p(来自 Linqpad):

var ints = new SortedSet<int>( new[] { 1,2,3,4,5,6,7,8,9,10});

var updatedEntries = ints.Where(i => i > 5); // No ToList()!
updatedEntries.Dump();

这显示6, 7, 8, 9, 10

ints.RemoveWhere(i => i > 7);
updatedEntries.Dump();

现在显示6, 7,因为updatedEntries 被重新执行。

ints.UnionWith(updatedEntries);

这会添加6, 7,而您希望它会添加第一个列表6, 7, 8, 9, 10

因此,在定义IEnumerable 时,您应该始终注意它的实际执行时间。它始终作用于该特定点的程序状态。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-07-25
    • 2017-03-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-11
    相关资源
    最近更新 更多