从列表中删除特定的字符串值

本文关键字:字符串 列表 删除 | 更新日期: 2023-09-27 18:17:07

我有一个字符串值列表,其中一些值在前面包含xxx或xxx。

xxxRed
xxxYellow
xxxxCareful with that axe Eugene!
xxxxxxdedicum aceasta frumoasa Melodia
xxxxLeaders
xxxxWorking Around - titles
XXXXXNothing To Fear
xxxxAvoiding standards
xxxFirst Aid
List<string> lstTitles = new List<string>();

这是我尝试过的

for (int i=0; i < lstTitles.Count; i++)
            {
                string title = lstTitles[i].ToLower().Trim();
                if (title[0] == 'x')
                {
                    lstTitles.Remove(lstTitles[i]);
                }
            }

我的问题是,只有一些值被删除,但不是全部。

是否有更好的方法来删除这些值?

从列表中删除特定的字符串值

使用RemoveAll方法

lstTitles.RemoveAll(s => s[0] == 'x' || s[0] == 'X');

,你可能想用StartsWith代替比较第一个字符。

lstTitles.RemoveAll(s => s.StartsWith("x",StringComparison.InvariantCultureIgnoreCase));

我的问题是,只有一些值被删除,但不是全部。

因为你跳过了项目。当您调用Remove()时,下一项将位于索引i处,但您将在下一个循环中增加i

它可以通过迭代列表的副本来解决,并删除原始列表中不需要的项:

foreach (var item in lstTitles.ToList())
{
    if (item.StartsWith("x", StringComparison.InvariantCultureIgnoreCase))
    {
        lstTitles.Remove(item);
    }
}

虽然这涉及到创建列表的副本,这不是很有用,以及调用Remove(),这本身是远远不够的性能。

所以你可以反转for循环,先删除最后一项,这不会改变未处理项的索引:

for (int i = lstTitles.Count - 1; i > 0; i--)
{
    if (lstTitles[i].StartsWith("x", StringComparison.InvariantCultureIgnoreCase))
    {
        lstTitles.RemoveAt(i);
    }
}

但正如@I4V指出的,所有这些逻辑已经在List<T>.RemoveAll()中,这是更好的阅读和可能优化了一些边缘情况,所以没有什么用处再手工编码。

这是因为你的跳过值。

假设列表包含['xVal1', 'xVal2', 'val3', 'xVal4', 'val5']。一开始你的i是0,你看list[0],它是'xVal1',所以你删除它。

现在您的列表包含['xVal2', 'val3', 'xVal4', 'val5'],并且您的i为1。你看一下list[1],它是'val3'。您忽略了xVal2 !

你可以从列表的后面开始,然后走到前面,尽管如果你删除了相同的值,你仍然会有潜在的错误。

更短的方法是使用LINQ:
var newList = lstTitles.Where(title=>!title.StartsWith('xxx'))

代替ToLower,你应该使用StartsWith的重载,它允许传递StringComparison.OrdinalIgnoreCase

然后使用List.RemoveAll,这是最易读,最有效和最短的方法:

lstTitles.RemoveAll(s => s.TrimStart().StartsWith("x", StringComparison.OrdinalIgnoreCase));

我认为,你最好这样创建一个新的列表

list = list
    .Where(i => ! i.StartsWith("xxx", StringComparison.InvariantCultureIgnoreCase))
    .ToList();

它的复杂度是O(n)然而,试图移除1 × 1的复杂度是O(n^2)

也可以这样做:

list.RemoveAll(i => i.StartsWith("xxx", StringComparison.InvariantCultureIgnoreCase));

处理所有情况,不需要第二个列表。