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

C# 从列表中删除特定的字符串值,c#,list,C#,List,我有一个字符串值列表,其中一些值前面包含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

我有一个字符串值列表,其中一些值前面包含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>();
xxxRed
xxxYellow
小心那把斧头,尤金!
XXXXXX德迪卡姆阿塞斯塔·弗鲁莫萨·梅洛迪亚酒店
三十三领导
xxxx解决方案-标题
没什么好害怕的
xxxxx避免标准
XXX急救
列表标题=新列表();
这就是我尝试过的

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

                }
            }
for(int i=0;i
我的问题是,只有部分值被删除,但不是全部

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

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

因为你跳过了项目。调用
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.RemoveAll()
中,它更易于阅读,并且可能针对某些边缘情况进行了优化,因此再次手工编写代码几乎没有用。

使用方法

您可能希望使用
StartsWith
而不是比较第一个字符

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

这是因为您正在跳过值

假设您的列表包含['xVal1'、'xVal2'、'val3'、'xVal4'、'val5']。首先,您的
i
是0,您查看列表[0],它是“xVal1”,所以您将其删除

现在,您的列表包含['xVal2'、'val3'、'xVal4'、'val5'],您的
i
为1。所以你们看一下列表[1],它是'val3'。你忽略了xVal2

您可以从列表的后面开始,然后转到前面,尽管如果删除了相同的值,您仍然会有一个潜在的bug

较短的方法是使用LINQ:

var newList = lstTitles.Where(title=>!title.StartsWith('xxx'))

您应该使用
StartsWith
的重载,而不是
ToLower
,该重载允许传递
StringComparison.ordinallingorecase

然后使用
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));

处理所有情况,并且没有第二个列表。

这将引发一个错误,因为集合在foreach循环中已被修改。@Sean不,没有,因为我调用了
.ToList()
。哦,对不起,错过了,我的坏=]所以在每次迭代中,您都要从旧集合创建一个新集合。这真是效率低下。@TimSchmelter就是这样。
|s[0]='X'
。。。此外,如果字符串项为null或为空,则将失败。不处理此情况,并且OP Nitened希望删除以“xxx”开头的项,而不是以“x”开头的项;)@实际上,OP的代码是错误的,因为它会从列表中删除“Xavier”。我肯定他不想这样,为什么循环一个列表会有>O(n)的复杂度?我指的是@CodeCaster的代码,它使用list.Remove(string),它本身在O(n)中。因此,如果在列表中循环,并且对于某些项,使用list.Remove(string),则组合复杂度可能为O(n^2)。
list.RemoveAll(i => i.StartsWith("xxx", StringComparison.InvariantCultureIgnoreCase));