【问题标题】:Is the ToArray method of a Stack<T> guaranteed to return in this order?Stack<T> 的 ToArray 方法是否保证按此顺序返回?
【发布时间】:2021-12-18 06:19:58
【问题描述】:

我有一个Stack&lt;T&gt;,我用它来堆叠整数元组。现在,我正在使用以下代码返回堆栈的副本,​​从最旧到最新排序:

public IEnumerable<Tuple<int,int>> GetAllTuples()
{
    return this.ToArray<Tuple<int,int>>().Reverse<Tuple<int,int>>();
}

这可行,但我担心ToArray() 返回的顺序可能无法在所有情况下都得到保证。 ToArray() 的文档说明如下:

元素以后进先出 (LIFO) 的顺序复制到数组中,类似于对 Pop 的连续调用返回的元素的顺序。

是否可以假设将来调用ToArray()(进而扩展为.Reverse())将返回相同的订单?我对“类似于”有点失望。如果没有,如何确保元组从最旧到最新返回?


为了进一步说明我的观点,这里有一个例子:

Stack<int> stack = new Stack<int>();
stack.Push(1);
stack.Push(2);
stack.Push(3);
stack.Push(4);
stack.Push(5);

int[] toArr = stack.ToArray<int>(); // Yields [5, 4, 3, 2, 1]
int[] toArrReverse = toArr.Reverse<int>(); // Yields [1, 2, 3, 4, 5], which is what I want.

【问题讨论】:

  • 该行为已记录在案。它不会改变。你有我的话:)
  • @500-InternalServerError 当我的代码中断时,我会追究你的责任;)
  • 使用Array.Reverse 可能更有效,因为它使用相同的数组。也许您应该使用Queue,它使用FIFO 而不是Stack,从而避免了Reverse
  • @Charlieface 在编辑时,语义上它的行为类似于堆栈。但是,当“完成”时,步骤是从最旧到最新跟踪的。此外,它只会包含少量元素(认为少于 10 个),因此排序仍然相对较快。

标签: c# stack


【解决方案1】:

根据文档,元素以后进先出 (LIFO) 顺序复制到数组中,类似于连续调用 Pop 返回的元素顺序。

因此,这看起来是一个完全定义订单的严格合同。没有说明这是特定于实现的,将来可能会发生变化。

所以,我相信我们现在和未来都可以依靠当前的行为。

【讨论】:

    【解决方案2】:

    This 来自 Microsoft 文档的文章说 ToArray

    将堆栈复制到一个数组中,以相同的顺序 Pop 将返回 项目。

    确认您正在观察的行为。

        // Copies the Stack to an array, in the same order Pop would return the items.
        public virtual Object[] ToArray()
        {
            Contract.Ensures(Contract.Result<Object[]>() != null);
    
            Object[] objArray = new Object[_size];
            int i = 0;
            while(i < _size) {
                objArray[i] = _array[_size-i-1];
                i++;
            }
            return objArray;
        }
    

    编辑:仔细想想,它是有道理的 - 根据定义,将项目从堆栈中取出的唯一方法是将它们弹出(后进先出)。当所有项目都被取出(或像 ToArray 一样被复制)时,情况也是如此。这一次只会发生一项。如果它的行为不是这样,恕我直言,这显然违反了 Stack 的核心思想。

    【讨论】:

    • 即使附上源代码,这也是一种奢侈。非常感谢您的快速回复。
    • 请注意源代码是针对非泛型 Stack 类型的。但是,我没有理由怀疑通用 Stack 可以以不同的方式实现相同的方法。
    • "当所有项目都被取出(或者只是像 ToArray 一样被复制)时,应该也是如此。这一次只会发生一个项目。" - 我不确定你在这里想说什么。不,它不会“一次一个项目”发生,因为整个数组将作为一个整体返回。 “如果它表现得不一样,恕我直言,它显然违反了 Stack 的核心理念。” - 有人可能争辩说,从堆栈中检索所有项目而不删除它们已经违反了该核心思想。另一方面,如果 peeking 没问题,那么 peeking 的顺序应该是无关紧要的。
    • “整个数组将作为一个整体返回”同意。但是该数组将在迭代中一次从堆栈中填充一项。核心思想是从堆栈中读取的这一项应该是它的最后一项。希望它能澄清我的答案。
    猜你喜欢
    • 2010-10-01
    • 2013-01-19
    • 2012-06-18
    • 2010-11-05
    • 2011-04-19
    • 2023-02-16
    • 2013-08-29
    • 2023-03-26
    相关资源
    最近更新 更多