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