如何从列表中“Dequeue”元素?

69

我有一个名为_deck的卡牌List

 private List<String> _deck = new List<String> {"2h", "3h", "4h", ... }

我想从 List 中删除一张卡并保存到一个变量中。我正在尝试执行以下操作:

 String p1FirstCard = _deck.RemoveAt(0);

但我遇到了错误

无法将类型 void 转换为 String

在 C# 中,List 是否有像 push/pop 一样的东西,但它在列表的“头”或“开头”执行此操作?(push/pop 在列表的“尾”或“末尾”工作。)

如果没有,那么我应该如何删除第一个元素但将其保存在变量中?


1
你为什么不使用 Queue<T> 呢? - Selman Genç
2
看起来你的卡牌列表被称为 '_deck'。 - lockstock
5个回答

69
如果你希望弹出队列的第一个元素,可以直接使用 Queue<T>
class Program
{
    static void Main(string[] args)
    {
        var _deck = new Queue<String>();
        _deck.Enqueue("2h");
        _deck.Enqueue("3h");
        _deck.Enqueue("4h");
        _deck.Enqueue("...");

        var first = _deck.Dequeue(); // 2h
        first = _deck.Dequeue(); // 3h
    }
}

如果您想弹出最后一个元素,可以使用 Stack<T>

class Program
{
    static void Main(string[] args)
    {
        var _deck = new Stack<String>();
        _deck.Push("2h");
        _deck.Push("3h");
        _deck.Push("4h");
        _deck.Push("...");

        var first = _deck.Pop(); // ...
        first = _deck.Pop(); // 4h
    }
}

也许你想要一个通用版本:msdn.microsoft.com/en-us/library/7977ey2c.aspx - AlexD
C#的Stack或Queue都不会从列表的末尾删除,这就是actionscript的pop()的工作方式。这并不意味着它们不是正确的选择,只是它们都不是完美的匹配。 - Bobson
@Bobson,我再次阅读了问题以确保自己没有错,但他在哪里要求删除最后一个元素?代码只显示删除第一个元素。 - Fredou
1
@Fredou - OP没有明确表示,但由于他引用了pop(),我认为这是他期望的行为。 - Bobson
@Bobson,这个问题很令人困惑,但我认为我同意你的观点。 - Fredou
2
Pop和Dequeue从列表的末尾删除。请参见此处:https://msdn.microsoft.com/zh-cn/library/system.collections.stack.pop(v=vs.110).aspx 或此处 https://msdn.microsoft.com/zh-cn/library/1c8bzx97(v=vs.110).aspx - Matthew Lock

60

您可以分两步进行:

String p1FirstCard = _deck[0];
_deck.RemoveAt(0);

您可以编写自己的扩展帮助方法(我添加了一个索引到Pop中,如@Fredou所建议的:
static class ListExtension
{
    public static T PopAt<T>(this List<T> list, int index)
    {
        T r = list[index];
        list.RemoveAt(index);
        return r;
    }
}

然后调用
String p1FirstCard = _deck.PopAt(0);

附注:名称可能有点令人困惑。通常情况下,Pop 会移除最后一个元素,而不是第一个元素。


也许你应该修改你的代码,使用一个参数来返回/删除一个索引项,这将给予OP所有可能的选择。 - Fredou
很好。对于一副洗过的牌,从牌堆顶部或底部抽取并没有什么区别,所以这太棒了。谢谢。 - Mc' Flips
在方法声明中添加 index = 0 可以将第一个元素作为默认操作移除,避免传递 index 参数。我认为这很有用,因为通常你想要移除第一个元素。 - GreatNews

6

AlexD的答案的基础上,我添加了更多的扩展方法:

public static class ListExtensionMethods
{
    public static T PopAt<T>(this List<T> list, int index)
    {
        var r = list[index];
        list.RemoveAt(index);
        return r;
    }

    public static T PopFirst<T>(this List<T> list, Predicate<T> predicate)
    {
        var index = list.FindIndex(predicate);
        var r = list[index];
        list.RemoveAt(index);
        return r;
    }

    public static T PopFirstOrDefault<T>(this List<T> list, Predicate<T> predicate) where T : class
    {
        var index = list.FindIndex(predicate);
        if (index > -1)
        {
            var r = list[index];
            list.RemoveAt(index);
            return r;
        }
        return null;
    }
}

4
如果你想要一个与pop()直接等价的方法,你需要自己编写,因为我认为List没有“从末尾删除并返回”的方法。但是,除了List之外,还有Queue(先进先出)和Stack(先进后出)类。

此外,还有LinkedList类,它可以让你从开头或结尾添加或删除元素,但提供的RemoveFirst()RemoveLast()方法不会自动返回被删除的项——你需要编写像AlexD这样的扩展方法来实现这一点。

所有这些都与从列表的开头或结尾删除内容有关。如果您只想从List的中间删除任意项,那么总是可以使用List.Remove(item)来删除特定项(而不是按位置)。

2
 private List<String> _deck = new List<String> {"2h", "3h", "4h", ... }
 //Save into variable first
 String p1FirstCard = _deck[0];
 //Now just remove it
 _deck.RemoveAt(0);

RemoveAt(int)不返回任何内容。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接