C# 如何从另一个列表中删除列表中的字符串?
我有两张名单,分别是listA和listB 我想删除listB中listA中的字符串,但我想这样做: 如果listA包含:“bar”、“bar”、“bar”、“foo” listB包含:“bar” 它仅移除1个条,结果将是: “酒吧”、“酒吧”、“富” 我编写的代码删除了所有“条”:C# 如何从另一个列表中删除列表中的字符串?,c#,string,list,duplicates,removeall,C#,String,List,Duplicates,Removeall,我有两张名单,分别是listA和listB 我想删除listB中listA中的字符串,但我想这样做: 如果listA包含:“bar”、“bar”、“bar”、“foo” listB包含:“bar” 它仅移除1个条,结果将是: “酒吧”、“酒吧”、“富” 我编写的代码删除了所有“条”: List result=listA.Except(listB.ToList(); 您可以尝试逐个删除它: foreach (var word in listB) listA.Remove(word); R
List result=listA.Except(listB.ToList();
您可以尝试逐个删除它:
foreach (var word in listB)
listA.Remove(word);
Remove方法一次只删除一个元素,并且在找不到项时不会引发异常(但返回false):var listA=new List(){“bar”、“bar”、“bar”、“foo”};
var listB=new List(){“bar”};
foreach(列表B中的var字){
删除(word);
}
这是一种更快的方法,但可能会更改第一个列表中元素的顺序。步骤:
- 将listA映射到一个
(我们称之为字典
),其中key是列表的元素,value是该值在listA中出现的总次数李>listAMap
- 迭代listB,对于listB的每个元素,如果该元素位于
中,则减少其计数李>listAMap
- 使用C#字典获取
的键,并遍历所有键。对于每个具有正值的键,将该键添加到另一个列表,并记录其总计数次数。因此,如果条目是listMapA
,则在新列表中添加两次“bar”“bar”->2
上述算法的支持代码:
//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.
//步骤1:创建字典。。。
var listAMap=新字典();
foreach(listA中的var listAElement)
{
listAMap.ContainsKey(listAElement)?listAMap[listAElement]+:listAMap.Add(listAElement,1);
}
//步骤2:从字典中删除listB元素。。。
foreach(列表B中的var listBElement)
{
如果(listAMap.Contains(listBElement))listAMap[listBElement]--;
}
//步骤3:从修剪过的字典创建新列表。。。
var prunedListA=新列表();
foreach(listAMap.Keys中的var键)
{
如果(listAMap[key],这里有一种更有效的方法:
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;
});
var countB=新字典(listB.Count);
foreach(列表B中的变量x)
{
整数计数;
countB.TryGetValue(x,out count);
countB[x]=计数+1;
}
listA.RemoveAll(x=>
{
整数计数;
如果(!countB.TryGetValue(x,out count))返回false;
如果(计数=1)
b.删除(x);
其他的
countB[x]=计数-1;
返回true;
});
您可以避免使用直接IndexOf获取位置的Contains调用。这样做效率很低,但您至少可以直接使用listA.Remove(word)
。不需要包含
。保留一些原始列表的顺序是否重要?这基本上是@Ian答案的副本,发布10多分钟后,您才想到类似的内容,但计算列表B,然后从列表a中删除匹配的项目(并减少匹配计数).无论如何,+1表示考虑效率。@IvanStoev:我们没有匹配列表中的项目。我们在字典中进行O(1)查找。说真的,解决方案非常简单(不是说你可以在答案上给出+2)。我也应该添加代码。当我从笔记本电脑访问时,我会这样做。@IvanStoev:现在需要做的最后一件事是将上面的代码分解成一个单独的方法,这样它会更干净。很好。但让我发布我想到的算法。正如我所说,类似的想法是O(m+n),但没有你所说的重新排序效果。顺便说一句,我不打算发布它,因为大多数人都喜欢一行,不关心性能。但一旦你分享了你的想法:)你错过了填充countB的步骤。@displayName我没有-试试看(提示-小行countB[x]=count+1;
):)哦,我明白了……我不知道字典中TryGetValue()
的这种行为。学到了一些新东西。
//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.
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;
});