简体   繁体   English

如何从另一个列表中删除列表中的字符串?

[英]How to remove strings in list from another list?

I have 2 list which names are listA and listB. 我有2个列表,其名称是listA和listB。

I want to remove strings in listB which are in listA, but I want to do this in this way: 我想删除listA中listB中的字符串,但我想以这种方式执行此操作:

if listA contains: "bar", "bar", "bar", "foo" and listB contains : "bar" 如果listA包含:“bar”,“bar”,“bar”,“foo”和listB包含:“bar”

it removes only 1 bar and the result will be: "bar", "bar", "foo" 它只删除1 bar,结果将是:“bar”,“bar”,“foo”

the code I wrote removes all "bar": 我写的代码删除所有“栏”:

List<string> result = listA.Except(listB).ToList();

You can try to remove it one by one: 您可以尝试逐个删除它:

foreach (var word in listB)
    listA.Remove(word);

The Remove method will only remove one element at a time and is not throwing exception (but returning false) when the item is not found: https://msdn.microsoft.com/en-us/library/cd666k3e(v=vs.110).aspx Remove方法一次只删除一个元素,并且在找不到该项时不会抛出异常(但返回false): https//msdn.microsoft.com/en-us/library/cd666k3e(v = vs。 110)的.aspx

var listA = new List<string>() { "bar", "bar", "bar", "foo" };
var listB = new List<string>() { "bar" };

foreach (var word in listB){
  listA.Remove(word);
}

This is a faster method but it is likely to change the order of elements of first list. 这是一种更快的方法,但它可能会改变第一个列表的元素顺序。 Steps: 脚步:

  • Map the listA to a Dictionary<string, int> (let's call it listAMap ), where key is the element of the list and value is the total number of times that value has occurred in listA; 将listA映射到Dictionary<string, int> (我们称之为listAMap ),其中key是列表的元素,value是listA中值发生的总次数;
  • Iterate through listB and for every element of listB, if that element is in the listAMap , reduce its count; 通过listB和listB的每个元素进行迭代,如果该元素在listAMap ,则减少其计数;
  • Get the keys of listMapA using Keys property of C# dictionaries, and iterate through all the keys. 使用C#词典的Keys属性获取listMapA ,并遍历所有键。 For every key which has positive value, add that key to another list a total of its count times. 对于具有正值的每个键,将该键添加到另一个列表中的总计数次数。 So if an entry is "bar" -> 2 , then add "bar" twice in the new list. 因此,如果条目是"bar" -> 2 ,则在新列表中添加两次“bar”。

Total run time of the algorithm is O(m + n) , where m and n are number of elements in both the original lists. 算法的总运行时间为O(m + n) ,其中m和n是两个原始列表中的元素数。 It is a better running time than other approaches mentioned here which have O(m * n) running time. 与这里提到的具有O(m * n)运行时间的其他方法相比,它是更好的运行时间。 Obviously this algorithm uses more space. 显然这个算法使用了更多的空间。


Supportive Code for the algorithm above: 上述算法的支持代码:

//Step-1: Create the dictionary...
var listAMap = new Dictionary<string, int>();
foreach (var listAElement in listA)
{
    listAMap.ContainsKey(listAElement) ? listAMap[listAElement]++ : listAMap.Add(listAElement, 1);
}

// Step-2: Remove the listB elements from dictionary...
foreach (var listBElement in listB)
{
    if (listAMap.Contains(listBElement)) listAMap[listBElement]--;
}

//Step-3: Create the new list from pruned dictionary...
var prunedListA = new List<string>();
foreach (var key in listAMap.Keys)
{
    if (listAMap[key] <= 0) continue;
    for (var count = 0; count < listAMap[key]; count++)
    {
        prunedListA.Add(key);
    }
}

//prunedListA contains the desired elements now.

Here is a more efficient way to do that: 这是一种更有效的方法:

var countB = new Dictionary<string, int>(listB.Count);
foreach (var x in listB)
{
    int count;
    countB.TryGetValue(x, out count);
    countB[x] = count + 1;
}
listA.RemoveAll(x =>
{
    int count;
    if (!countB.TryGetValue(x, out count)) return false;
    if (count == 1)
        countB.Remove(x);
    else
        countB[x] = count - 1;
    return true;
});

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

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