如何从另一个列表中删除列表中的字符串?
How to remove strings in list from another list?
我有 2 个列表,名称是 listA 和 listB。
我想删除 listB 中的字符串,而这些字符串在 listA 中,但我想这样做:
如果列表 A 包含:"bar"、"bar"、"bar"、"foo"
listB 包含:"bar"
它只删除了 1 个柱,结果将是:
"bar"、"bar"、"foo"
我写的代码删除了所有 "bar":
List<string> result = listA.Except(listB).ToList();
您可以尝试一一删除:
foreach (var word in listB)
listA.Remove(word);
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);
}
这是一种更快的方法,但它可能会更改第一个列表中元素的顺序。步骤:
- 将 listA 映射到
Dictionary<string, int>
(我们称之为 listAMap
),其中 key 是列表的元素,value 是该值在 listA 中出现的总次数;
- 遍历 listB 并针对 listB 的每个元素,如果该元素在
listAMap
中,则减少其计数;
- 使用C#字典的Keys property获取
listMapA
的键,并遍历所有键。对于每个具有正值的键,将该键添加到另一个列表总计其计数次数。因此,如果条目是 "bar" -> 2
,则在新列表中添加两次 "bar"。
算法的总 运行 时间是 O(m + n),其中 m 和 n 是两个原始列表中的元素数。这是一个更好的 运行ning 时间比这里提到的其他方法有 O(m * n) 运行ning 时间。显然这个算法使用了更多的space.
上述算法的支持代码:
//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;
});
我有 2 个列表,名称是 listA 和 listB。
我想删除 listB 中的字符串,而这些字符串在 listA 中,但我想这样做:
如果列表 A 包含:"bar"、"bar"、"bar"、"foo" listB 包含:"bar"
它只删除了 1 个柱,结果将是: "bar"、"bar"、"foo"
我写的代码删除了所有 "bar":
List<string> result = listA.Except(listB).ToList();
您可以尝试一一删除:
foreach (var word in listB)
listA.Remove(word);
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);
}
这是一种更快的方法,但它可能会更改第一个列表中元素的顺序。步骤:
- 将 listA 映射到
Dictionary<string, int>
(我们称之为listAMap
),其中 key 是列表的元素,value 是该值在 listA 中出现的总次数; - 遍历 listB 并针对 listB 的每个元素,如果该元素在
listAMap
中,则减少其计数; - 使用C#字典的Keys property获取
listMapA
的键,并遍历所有键。对于每个具有正值的键,将该键添加到另一个列表总计其计数次数。因此,如果条目是"bar" -> 2
,则在新列表中添加两次 "bar"。
算法的总 运行 时间是 O(m + n),其中 m 和 n 是两个原始列表中的元素数。这是一个更好的 运行ning 时间比这里提到的其他方法有 O(m * n) 运行ning 时间。显然这个算法使用了更多的space.
上述算法的支持代码:
//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;
});