2013-10-23 65 views
5

我有一個字符串數組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中的所有內容,位是否是最快的方法?

+2

你的意思是你想從X包含任何y的元素如子的所有元素中刪除?另外:你說「陣列」,你的意思是「列表」? –

+1

如果Y1只是「bb」,X1應該被刪除嗎? – Corak

+0

是的,它應該是交叉引用。 – Kovu

回答

1

對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; 
     } 
    } 
} 

這應該這樣做(請注意,這個代碼不進行測試)。

+0

我已經提出了相同的答案,但被投票通過了!? +1爲你的答案,這是我同意將是最好的方法。 –

9

方便

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); 
} 

此:

  • 不分配陣列(輸出Splitparams char[]Split
  • 不會產生任何新的string實例(爲Split輸出)
  • 不使用委託抽象
  • 沒有抓獲範圍
  • 使用的List<T>struct定製迭代器,而不是class迭代IEnumerable<T>
  • 啓動新List<T>與適當的最壞情況下的大小,以避免重新分配
+0

@DeeMac請參閱編輯,這樣可以避免因'Split' –

+0

+1而引起的分配。有趣的是在令牌搜索上看到你的代碼,我之前沒有看到過。 –

+0

@DeeMac它實際上是從我昨天寫的一些stackoverflow.com代碼中取代了一些正在尋找匹配形式的代碼''abc; def; ghij「' - 舊代碼正在執行'Split',並且我們看到很多從重複的字符串(和數組)緩慢填充內存的開銷 - 即**每個**請求都會導致額外的「abc」,「def」,「ghij」和新的'串[3]'。在stackoverflow.com上,快速填充... –

1

我認爲一個相當快的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」,所以我忽略了字符串數組位)。

+0

包含在這裏是不可靠的,因爲「aaa.bbbb.ccc」包含「bbb」,但我不會認爲這是一個「匹配」 –

+0

@MarcGravell OP在這方面是含糊不清的。正如你所看到的,我要求澄清。 –

0

如果你有一個相對較小的列表,性能分支並不是什麼大不了的事情。這是我能想到的最簡單的foreach解決方案。

List<string> ListZ = ListX.ToList(); 

foreach (string x in ListX) 
{ 
    foreach (string y in ListY) 
    { 
     if (x.Contains(y)) 
      ListZ.Remove(x); 
    } 
} 
+1

這有點棘手 - 如果'Y'有'''bbb「',是否會導致''aaa.bbbbb.ccc」'被刪除?好吧,它會* - 但應該嗎? (這可能更多的是OP的問題) –

1

試試這個,使用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; 
    }); 
+0

這是一大堆「分裂」......如果目標是*方便*,它可以在一行中完成;如果目標是*性能*,那麼:有更好的方法 –

+0

@MarcGravell,謝謝,我改進了每次迭代只做一次分裂的答案。 –