简体   繁体   English

从List中删除特定的字符串值

[英]removing specific string values from a List

I have a List of string values and and some of the values contains xxx or XXX in front. 我有一个字符串值列表,其中一些值包含前面的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>();

This is what I have tried 这就是我尝试过的

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

                }
            }

Problem I have is that only some of the values are removed but not all of them. 我遇到的问题是只删除了一些值但不是全部。

Is there perhaps a better way of removing these values? 是否有更好的方法来消除这些价值观?

Use RemoveAll method 使用RemoveAll方法

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

and you may want to use StartsWith instead of comparing first char. 并且您可能希望使用StartsWith而不是比较第一个char。

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

Problem I have is that Only some of the values are removed but not all of them. 我遇到的问题是只删除了一些值而不是全部值。

Because you're skipping items. 因为你正在跳过物品。 When you call Remove() , the next item will be at index i , but you'll increase i in the next loop. 当你调用Remove() ,下一个项目将在索引i ,但你将在下一个循环中增加i

It can be solved by iterating over a copy of the list, and removing unwanted items in the original: 它可以通过迭代列表的副本,并删除原始中不需要的项目来解决:

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

Though this involves creating a copy of the list, which isn't really useful, as well as calling Remove() which itself is far from performant. 虽然这涉及创建列表的副本,这并不是真正有用,并且调用Remove()本身远远不能实现。

So you could invert your for-loop, to remove the last items first which doesn't change the indexing for unprocessed items: 因此,您可以反转for循环,先删除最后一项不会更改未处理项目索引的项目:

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

But as @I4V points out, all of this logic already is in List<T>.RemoveAll() , which is nicer to read and probably optimized for some edge cases, so there's little use to hand-code it again. 但是正如@ I4V指出的那样,所有这些逻辑都已经在List<T>.RemoveAll() ,它更好读取并且可能针对某些边缘情况进行了优化,因此再次手动编码几乎没有用处。

That's because your skipping values. 那是因为你跳过了价值观。

Suppose your list contains ['xVal1', 'xVal2', 'val3', 'xVal4', 'val5']. 假设您的列表包含['xVal1','xVal2','val3','xVal4','val5']。 At first your i is 0, and you look at list[0], which is 'xVal1', so you remove it. 首先你的i是0,你看一下list [0],它是'xVal1',所以你删除它。

Now your list contains ['xVal2', 'val3', 'xVal4', 'val5'], and your i is 1. So you look at list[1] which is 'val3'. 现在你的列表包含['xVal2','val3','xVal4','val5'],你的i是1.所以你看一下列表[1]是'val3'。 You ignored xVal2 ! 你忽略了xVal2!

You can start at the back of the list and go to the front, although you will still have a potential bug in case there are identical values you remove. 您可以从列表的后面开始并转到前面,但是如果您删除了相同的值,您仍然会有潜在的错误。

A shorter way would be to use LINQ: 更简单的方法是使用LINQ:

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

Instead of ToLower you should use the overload of StartsWith which allows to pass a StringComparison.OrdinalIgnoreCase . 您应该使用StartsWith的重载代替ToLower ,它允许传递StringComparison.OrdinalIgnoreCase

Then use List.RemoveAll which is the most readable, most efficient and shortest approach: 然后使用List.RemoveAll ,这是最可读,最有效和最短的方法:

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

Demo 演示

I think, you'd better just create a new list this way 我想,你最好用这种方式创建一个新列表

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

It would have a O(n) complexity whereas, trying to remove then 1 by 1 would be in O(n^2). 它将具有O(n)复杂度,而试图将1然后1移除将是O(n ^ 2)。

This could work also : 这也可以工作:

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

Handles all cases and without a second list. 处理所有案例,没有第二个列表。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM