2014-10-20 78 views
0

有沒有辦法從當前字符數組中刪除字符,然後將其保存到新的字符數組中。以下是代碼:刪除字符數組中的字符

string s1 = "move"; 
string s2 = "remove"; 
char[] c1 = s1.ToCharArray(); 
char[] c2 = s2.ToCharArray(); 

for (int i = 0; i < s2.Length; i++) 
{ 
    for (int p = 0; p < s1.Length; p++) 
    { 
    if (c2[i] == c1[p]) 
    { 
     // REMOVE LETTER FROM C2 
    } 


    // IN THE END I SHOULD JUST HAVE c3 = re (ALL THE MATCHING CHARACTERS M-O-V-E SHOULD BE 
     DELETED)        

會感謝你的幫助

+0

爲什麼不直接使用'string'? – 2014-10-20 07:58:49

+3

也許你想'var c3 = s2.Replace(s1,「」).ToCharArray();'但如果你從'remove'中刪除'm','o','v'和'e',用'r',因爲你會刪除兩個'e'。也許你應該解釋你最終想做什麼。 – 2014-10-20 08:00:32

+0

是的,請澄清。你是簡單地刪除一個子字符串,還是刪除remove數組中的所有字符,還是隻刪除move數組中每個字符的第一個出現? – 2014-10-20 08:13:07

回答

0

這不是特別有效,但它可能會是足夠快的短字符串:

string s1 = "move"; 
string s2 = "remove"; 

foreach (char charToRemove in s1) 
{ 
    int index = s2.IndexOf(charToRemove); 

    if (index >= 0) 
     s2 = s2.Remove(index, 1); 
} 

// Result is now in s2. 

Console.WriteLine(s2); 

這避免了轉換成字符數組。

但是,只是強調:這將是非常慢的大字符串。

[編輯]

我已經做了一些測試,事實證明,這個代碼就是相當快。

在這裏,我將代碼與來自另一個答案的優化代碼進行比較。但是請注意,我們沒有完全公平地進行比較,因爲這裏的代碼正確地實現了OP的要求,而其他代碼卻沒有。但是,它確實證明了HashSet的使用沒有人們想象的那麼有用。我在一個發佈版本上測試了這段代碼,沒有在一個調試器中運行(如果你在一個調試器中運行它,它會執行一個調試版本,而不是一個發佈版本,它會給出不正確的時序)。

該測試使用長度爲1024的字符串和字符來刪除== "SKFPBPENAALDKOWJKFPOSKLW"

我的結果,其中test1()是另一個答案不正確的,但所謂最優的解決方案,並test2()是我的未經優化的,但正確的解決辦法:

test1() took 00:00:00.2891665 
test2() took 00:00:00.1004743 

test1() took 00:00:00.2720192 
test2() took 00:00:00.0993898 

test1() took 00:00:00.2753971 
test2() took 00:00:00.0997268 

test1() took 00:00:00.2754325 
test2() took 00:00:00.1026486 

test1() took 00:00:00.2785548 
test2() took 00:00:00.1039417 

test1() took 00:00:00.2818029 
test2() took 00:00:00.1029695 

test1() took 00:00:00.2727377 
test2() took 00:00:00.0995654 

test1() took 00:00:00.2711982 
test2() took 00:00:00.1009849 

正如你所看到的,test2()一貫優於test1()。即使串被增加到長度。這保持爲真8192

測試代碼:

using System; 
using System.Collections.Generic; 
using System.Diagnostics; 
using System.Text; 

namespace Demo 
{ 
    public static class Program 
    { 
     private static void Main(string[] args) 
     { 
      var sw = new Stopwatch(); 

      string text = randomString(8192, 27367); 
      string charsToRemove = "SKFPBPENAALDKOWJKFPOSKLW"; 

      int dummyLength = 0; 

      int iters = 10000; 

      for (int trial = 0; trial < 8; ++trial) 
      { 
       sw.Restart(); 

       for (int i = 0; i < iters; ++i) 
        dummyLength += test1(text, charsToRemove).Length; 

       Console.WriteLine("test1() took " + sw.Elapsed); 

       sw.Restart(); 

       for (int i = 0; i < iters; ++i) 
        dummyLength += test2(text, charsToRemove).Length; 

       Console.WriteLine("test2() took " + sw.Elapsed); 

       Console.WriteLine(); 
      } 
     } 

     private static string randomString(int length, int seed) 
     { 
      var rng = new Random(seed); 
      var sb = new StringBuilder(length); 

      for (int i = 0; i < length; ++i) 
       sb.Append((char) rng.Next(65, 65 + 26*2)); 

      return sb.ToString(); 
     } 

     private static string test1(string text, string charsToRemove) 
     { 
      HashSet<char> excludeCharacters = new HashSet<char>(charsToRemove); 
      StringBuilder sb = new StringBuilder(); 

      foreach (char ch in text) 
      { 
       if (!excludeCharacters.Contains(ch)) 
       { 
        sb.Append(ch); 
       } 
      } 

      return sb.ToString(); 
     } 

     private static string test2(string text, string charsToRemove) 
     { 
      foreach (char charToRemove in charsToRemove) 
      { 
       int index = text.IndexOf(charToRemove); 

       if (index >= 0) 
        text = text.Remove(index, 1); 
      } 

      return text; 
     } 
    } 
} 

[EDIT 2]

這裏的一個更優化的解決方案:

public static string RemoveChars(string text, string charsToRemove) 
{ 
    char[] result = new char[text.Length]; 
    char[] targets = charsToRemove.ToCharArray(); 
    int n = 0; 
    int m = targets.Length; 

    foreach (char ch in text) 
    { 
     if (m == 0) 
     { 
      result[n++] = ch; 
     } 
     else 
     { 
      int index = findFirst(targets, ch, m); 

      if (index < 0) 
      { 
       result[n++] = ch; 
      } 
      else 
      { 
       if (m > 1) 
       { 
        --m; 
        targets[index] = targets[m]; 
       } 
       else 
       { 
        m = 0; 
       } 
      } 
     } 
    } 

    return new string(result, 0, n); 
} 

private static int findFirst(char[] chars, char target, int n) 
{ 
    for (int i = 0; i < n; ++i) 
     if (chars[i] == target) 
      return i; 

    return -1; 
} 

將其插入我上面的測試程序中顯示,它的運行速度比test2()快3倍。

+0

這是非常緩慢的,這個特定的結果可以在O(N)而不是O(N^2)中完成,就像這裏一樣。所以,不,這似乎不是一個好的答案。 – 2014-10-20 17:22:13

+0

@PeterDuniho如果字符串雖然很小(並且可能比更復雜的實現更快),但這是一個非常好的答案。它非常依賴於要求。它還具有實際實現OP要求的優點。 – 2014-10-21 07:39:12

+0

事實上,OP並沒有以有用的方式澄清任何事情,因爲他的新解釋並不十分清楚。也就是說,即使我們假設你已經成功地解決了他的需求,這仍然不是一個有效的解決方案。即使O(N^2)可以接受,不必要地分配新對象也不會。對於s2使用StringBuilder,而不是每次要刪除字符時都生成新的字符串實例。 – 2014-10-21 08:10:01

0

您可以創建第三個數組c3,您將在其中添加c2中不會被刪除的字符。您也可以使用Replace

string s3 = s2.Replace(s1,""); 
0

最初的O(N^2)方法是浪費的。我不明白其他兩個答案是如何實際執行你似乎試圖完成的工作的。我希望這個例子,它有O(N)的性能,適合你的更好:

string s1 = "move"; 
string s2 = "remove"; 
HashSet<char> excludeCharacters = new HashSet<char>(s1); 
StringBuilder sb = new StringBuilder(); 

// Copy every character from the original string, except those to be excluded 
foreach (char ch in s2) 
{ 
    if (!excludeCharacters.Contains(ch)) 
    { 
     sb.Append(ch); 
    } 
} 

return sb.ToString(); 

誠然,對於短字符串的表現並不容易事。但恕我直言,這也比其他選擇更容易理解。

編輯:

它仍然是不完全清楚,我什麼OP是想在這裏做。最明顯的任務是刪除整個單詞,但他的描述似乎都沒有說這就是他真正想要的。因此,假設上述不符合他的需求,但他也不想刪除整個單詞,這裏有幾個其他選項...

1)O(N),最好的方法對於非平凡長度的字符串,但稍微複雜一些:

string s1 = "move"; 
string s2 = "remove"; 
Dictionary<char, int> excludeCharacters = new Dictionary<char, int>(); 

foreach (char ch in s1) 
{ 
    int count; 

    excludeCharacters.TryGetValue(ch, out count); 
    excludeCharacters[ch] = ++count; 
} 

StringBuilder sb = new StringBuilder(); 

foreach (char ch in s2) 
{ 
    int count; 

    if (!excludeCharacters.TryGetValue(ch, out count) || count == 0) 
    { 
     sb.Append(ch); 
    } 
    else 
    { 
     excludeCharacters[ch] = --count; 
    } 
} 

return sb.ToString(); 

2)O(N^2)實現,其中至少其中,如果所有的輸入相對較短就足夠了其他不必要的低效率和最小化:

StringBuilder sb = new StringBuilder(s2); 

foreach (char ch in s1) 
{ 
    for (int i = 0; i < sb.Length; i++) 
    { 
     if (sb[i] == ch) 
     { 
      sb.Remove(i, 1); 
      break; 
     } 
    } 
} 

return sb.ToString(); 
+0

這不會考慮字符的順序,是嗎? – 2014-10-20 08:34:58

+0

哪個訂單?新字符串中的字符將與原始s2字符串中的順序相同。 s1字符串中的字符順序無關緊要。在OP的例子中,每個只是從原始字符串中刪除,而不考慮順序,所以這個例子也不考慮s1中字符的順序。 – 2014-10-20 08:41:13

+1

事情是這樣的,對於OP的問題,這返回「r」,但是他聲明他想要「返回」。 (另外,最好把它寫成'string result = new string(s2.Except(s1).ToArray());'無論如何。) – 2014-10-20 08:45:03