从字符串数组中删除列表中的内容
本文关键字:列表 删除 字符串 数组 删除列 | 更新日期: 2023-09-27 18:36:44
我有一个字符串数组x和一个列表y,我想从列表X中删除Y中的所有数据,如何以最快的方式做到这一点?
例如:X:1) "aaa.bbb.ccc"2) "ddd.eee.fff"3) "ggg.hhh.jjj"
Y:1)"啪"2)"FFF"
结果应该是一个新的列表,其中只有 3) 存在,因为 X.1 被 Y.1 删除,X.2 被 Y.2 删除
怎么做?
我知道我可以在列表 X 上做一个 foreach 并检查列表 Y 中的所有内容,这是最快的方法吗?
最方便的是
var Z = X.Where(x => !x.Split('.').Intersect(Y).Any()).ToList();
这与"最快"不同。最快的(运行时)方法是使用令牌搜索,例如:
public static bool ContainsToken(string value, string token, char delimiter = '.')
{
if (string.IsNullOrEmpty(token)) return false;
if (string.IsNullOrEmpty(value)) return false;
int lastIndex = -1, idx, endIndex = value.Length - token.Length, tokenLength = token.Length;
while ((idx = value.IndexOf(token, lastIndex + 1)) > lastIndex)
{
lastIndex = idx;
if ((idx == 0 || (value[idx - 1] == delimiter))
&& (idx == endIndex || (value[idx + tokenLength] == delimiter)))
{
return true;
}
}
return false;
}
然后像这样:
var list = new List<string>(X.Length);
foreach(var x in X)
{
bool found = false;
foreach(var y in Y)
{
if(ContainsToken(x, y, '.'))
{
found = true;
break;
}
}
if (!found) list.Add(x);
}
这:
- 不分配数组(对于
Split
的输出,对于Split
的params char[]
) - 不创建任何新的
string
实例(对于Split
的输出) - 不使用委托抽象
- 没有捕获的范围
- 使用
List<T>
的struct
自定义迭代器,而不是IEnumerable<T>
的class
迭代器 - 以适当的最坏情况大小启动新
List<T>
以避免重新分配
遍历 X 和 Y 确实是最快的选择,因为您有这个包含约束。我真的看不到任何其他方法。
不过,它不应该是 X 的foreach
,因为您无法修改使用 foreach
迭代的集合。
所以一个选项是:
for (int counterX = 0; counterX < X.Length; counterX++)
{
for(int counterY = 0; counterY < Y.Length; counterY++)
{
if (X[counterX].Contains(Y[counterY]))
{
X.RemoveAt(counterX--);
counterY = Y.Length;
}
}
}
这应该可以做到(请注意,此代码未经测试)。
我认为一个相当快的方法是使用List的内置RemoveAll()
方法:
List<string> x = new List<string>
{
"aaa.bbb.ccc",
"ddd.eee.fff",
"ggg.hhh.jjj"
};
List<string> y = new List<string>
{
"bbb",
"fff"
};
x.RemoveAll(s => y.Any(s.Contains));
(请注意,我假设您有两个列表,x 和 y。您的 OP 提到了一个字符串数组,但随后继续谈论"列表 X"和"列表 Y",所以我忽略了字符串数组位。
试试这个,使用Aggregate
函数
var xArr = new string[] { "aaa.bbb.ccc", "ddd.eee.fff", "ggg.hhh.jjj" };
var yList = new List<string> { "bbb", "fff" };
var result = xArr.Aggregate(new List<string> { }, (acc, next) =>
{
var elems = next.Split('.');
foreach (var y in yList)
if (elems.Contains(y))
return acc;
acc.Add(next);
return acc;
});
如果你有一个相对较小的列表,那么性能影响就不是什么大问题了。这是我能想到的最简单的解决方案。
List<string> ListZ = ListX.ToList();
foreach (string x in ListX)
{
foreach (string y in ListY)
{
if (x.Contains(y))
ListZ.Remove(x);
}
}