我有一個字符串數組x和一個列表y我想從列表X中刪除Y中的所有數據,如何以最快的方式做到這一點?從字符串數組中刪除什麼在列表中
例如: X: 1) 「aaa.bbb.ccc」 2) 「ddd.eee.fff」 3) 「ggg.hhh.jjj」
Y: 1)「BBB 「 2)‘FFF’
結果應該是一個新的列表,其中只有3個)存在,因爲X.1得到由Y.1刪除和十,得到由Y.2
怎麼做刪除那?
我知道我可以在列表X中做一個foreach並檢查列表Y中的所有內容,位是否是最快的方法?
我有一個字符串數組x和一個列表y我想從列表X中刪除Y中的所有數據,如何以最快的方式做到這一點?從字符串數組中刪除什麼在列表中
例如: X: 1) 「aaa.bbb.ccc」 2) 「ddd.eee.fff」 3) 「ggg.hhh.jjj」
Y: 1)「BBB 「 2)‘FFF’
結果應該是一個新的列表,其中只有3個)存在,因爲X.1得到由Y.1刪除和十,得到由Y.2
怎麼做刪除那?
我知道我可以在列表X中做一個foreach並檢查列表Y中的所有內容,位是否是最快的方法?
對X和Y的迭代確實是最快的選擇,因爲你有這個包含約束。我真的沒有看到任何其他的方式。
應該不是foreach
過X,但因爲你不能修改你迭代與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;
}
}
}
這應該這樣做(請注意,這個代碼不進行測試)。
我已經提出了相同的答案,但被投票通過了!? +1爲你的答案,這是我同意將是最好的方法。 –
最方便將
var Z = X.Where(x => !x.Split('.').Intersect(Y).Any()).ToList();
這是不一樣的 「最快」。也許最快時(runtime)的方式來做到這一點是使用令牌的搜索,如:
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
,params char[]
的Split
)string
實例(爲Split
輸出)List<T>
的struct
定製迭代器,而不是class
迭代IEnumerable<T>
List<T>
與適當的最壞情況下的大小,以避免重新分配@DeeMac請參閱編輯,這樣可以避免因'Split' –
+1而引起的分配。有趣的是在令牌搜索上看到你的代碼,我之前沒有看到過。 –
@DeeMac它實際上是從我昨天寫的一些stackoverflow.com代碼中取代了一些正在尋找匹配形式的代碼''abc; def; ghij「' - 舊代碼正在執行'Split',並且我們看到很多從重複的字符串(和數組)緩慢填充內存的開銷 - 即**每個**請求都會導致額外的「abc」,「def」,「ghij」和新的'串[3]'。在stackoverflow.com上,快速填充... –
我認爲一個相當快的Appro公司ACH是使用列表的內置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」,所以我忽略了字符串數組位)。
包含在這裏是不可靠的,因爲「aaa.bbbb.ccc」包含「bbb」,但我不會認爲這是一個「匹配」 –
@MarcGravell OP在這方面是含糊不清的。正如你所看到的,我要求澄清。 –
如果你有一個相對較小的列表,性能分支並不是什麼大不了的事情。這是我能想到的最簡單的foreach解決方案。
List<string> ListZ = ListX.ToList();
foreach (string x in ListX)
{
foreach (string y in ListY)
{
if (x.Contains(y))
ListZ.Remove(x);
}
}
這有點棘手 - 如果'Y'有'''bbb「',是否會導致''aaa.bbbbb.ccc」'被刪除?好吧,它會* - 但應該嗎? (這可能更多的是OP的問題) –
試試這個,使用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;
});
這是一大堆「分裂」......如果目標是*方便*,它可以在一行中完成;如果目標是*性能*,那麼:有更好的方法 –
@MarcGravell,謝謝,我改進了每次迭代只做一次分裂的答案。 –
你的意思是你想從X包含任何y的元素如子的所有元素中刪除?另外:你說「陣列」,你的意思是「列表」? –
如果Y1只是「bb」,X1應該被刪除嗎? – Corak
是的,它應該是交叉引用。 – Kovu