从字符串数组中删除最后一个项目

60

我正在开发一个简单的二十一点游戏项目。首先,我创建了牌的数组:

string[] deck = { "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A", };

然后将其乘以4,并赋给deckNumber

newDeck = Enumerable.Repeat(deck, deckNumber*4).SelectMany(x => x).ToArray();

当我想从数组中删除最后一张卡片时,我会使用以下方法:
newDeck = newDeck.Where(w => w != newDeck.Last()).ToArray();

所以问题在于代码没有从数组中删除最后一个元素,就像有多个数组一样,并且从它们所有的末尾元素中删除。例如,在一个牌组中:
cards: 2 3 4 5 6 7 8 9 10 J Q K A 2 3 4 5 6 7 8 9 10 J Q K A 2 3 4 5 6 7 8 9 10 J Q K A 2 3 4 5 6 7 8 9 10 J Q K A 

当我使用我的 remove 命令时,它变成了:
cards: 2 3 4 5 6 7 8 9 10 J Q K 2 3 4 5 6 7 8 9 10 J Q K 2 3 4 5 6 7 8 9 10 J Q K 2 3 4 5 6 7 8 9 10 J Q K 

它从数组中删除所有的A。但是我只想从整个数组中删除最后一个项目。问题出在哪里,我该如何解决?


3
w => w != newDeck.Last() 中,你正在比较字符串,所以所有的字符串 "A" 都被认为是相等的,这就是为什么所有的 A 都被移除了。(字符串是按值而非引用进行比较)。 - Daniel J.G.
值得一读:https://dev59.com/wHNA5IYBdhLWcg3wfN2O - Stephen Kennedy
4个回答

106

要仅删除最后一个元素,请使用以下方法:

newDeck = newDeck.Take(newDeck.Count() - 1).ToArray();

你的解决方案会移除所有等于最后一个元素的元素。对于字符串来说,这意味着它会移除所有等于A的元素。


2
你可以使用.SkipLast(1)代替newDeck.Take(newDeck.Count() - 1) - felixfbecker
4
SkipLast() 不是标准的 LINQ 方法,它是在第三方项目中实现的,例如 MoreLinq - Flat Eric
是的,它就是这样的:https://learn.microsoft.com/zh-cn/dotnet/api/system.linq.enumerable.skiplast - felixfbecker
5
这是一个 .NET Core 的方法。大多数人仍在使用常规的 .NET Framework。 - Dmytro Shevchenko
我刚试了一下这个方法(.Take)和Ahmet的方法(.Resize),发现.Resize速度一直都比较快。我是说一直,我可以打赌一大笔钱。数组越长,差异越大。 - Andrew Steitz
@DmytroShevchenko:有趣的是它在.NET 2.0标准中... - nomen

47
你可以使用 Array 类来调整大小:
Array.Resize(ref result, result.Length - 1);

它创建一个指定大小的新数组,并将元素复制到新数组中。它实际上并不调整数组的大小,名称有点误导。

实际上,无法调整数组的大小。数组是固定集合。这是为了保持数组实现的效率而设计的。


8
我刚刚尝试了这种方法和Flat Eric的方法(.Take),这种方法(.Resize)始终更快。我是说一直如此,就像我会下巨额赌注一样。数组越长,差异越大。 - Andrew Steitz
同意。速度提升也很不错。;-) - Andrew Steitz

16

如果您使用C# 8.0(与.net 3.0一起发布),则很容易删除数组的最后一项。

您可以结合“帽子”^运算符和范围..运算符来删除最后一个项目:

newDeck = newDeck[..^1];  // all items in the array except the last

^..的其他一些示例:

var lastItem   = newDeck[^1];    // last item in array
var allItems   = newDeck[..];    // all items
var skipTwo    = newDeck[2..];   // all items except the first 2 items
var innerItems = newDeck[1..^1]  // all items except the first and last

在线演示


该死,我不知道这种奇怪的事情是可能的。也许在 Kotlin 或其他语言中可以实现,但在 C# 中? - Damn Vegetables

12

@Flat Eric解释了为什么你的解决方案不起作用。

这里有一个删除最后一个元素的替代方法:

newDeck = newDeck.Reverse().Skip(1).Reverse().ToArray();

澄清:

[a, b, c] => Reverse => [c, b, a] => Skip(1) => [b, a] => Reverse() => [a, b]

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