2014-10-20 5 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

단순히 '문자열'을 사용하지 않는 이유는 무엇입니까? –

+3

아마도'var c3 = s2.Replace (s1, "") .ToCharArray();'를 원하지만'm','o','v' 및'e'를'remove'에서 제거하면 남게됩니다. 'r'을 사용하면'e'를 모두 제거 할 수 있기 때문입니다. 아마 당신이 궁극적으로하고 싶은 것을 설명해야합니다. –

+0

예, 명확히하십시오. 단순히 하위 문자열을 제거 하시겠습니까? 아니면 remove 배열의 모든 문자를 제거 하시겠습니까? 아니면 move 배열의 각 문자가 처음 나오는 것을 제거하고 있습니까? –

답변

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

이 피하는로 변환 char 배열.

그러나 강조하기 위해 : 이것은 큰 문자열의 경우 매우 느립니다.

[편집]

나는 몇 가지 테스트를 수행 한하고이 코드가 꽤 빨리 사실에 있음을 밝혀졌습니다.

여기 코드를 다른 답변의 최적화 된 코드와 비교합니다. 그러나 여기에서는 코드가 OP의 요구 사항을 올바르게 구현하고 있으므로 다른 코드는 올바르게 구현하지 않기 때문에 전체적으로 공정하게 비교하지는 않습니다. 그러나 HashSet을 사용하면 생각만큼 도움이되지 않는다는 것을 보여줍니다.

디버거에서 실행하지 않고 릴리스 빌드에서이 코드를 테스트했습니다 (디버거에서 실행하는 경우 디버그 빌드는 잘못된 타이밍을 제공하는 릴리스 빌드가 아닙니다).

이 테스트에서는 길이가 1024 인 대상 문자열을 사용하고 제거 할 문자는 == "SKFPBPENAALDKOWJKFPOSKLW"입니다.

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()을 능가하는 성능 : test1()는 다른 답변에서 잘못된하지만 가정으로 최적화 된 솔루션이다

내 결과 및 test2() 내 최적화되지 않은 있지만 올바른 솔루션입니다. 문자열의 길이가 증가하는 경우에도 마찬가지 남아 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; 
     } 
    } 
} 

[수정 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^2) 대신 O (N)에서 수행 할 수 있습니다. 그래서, 아니오 ... 이것은 좋은 대답처럼 보이지 않습니다. –

+0

@PeterDuniho 문자열이 작 으면 (그리고 더 복잡한 구현보다 빠를 가능성이 높습니다.) 완벽하게 좋은 대답입니다. 요구 사항에 따라 달라집니다. 또한 OP의 요구 사항을 실제로 구현한다는 장점이 있습니다. –

+0

사실 OP는 새로운 설명이 끔찍한 것이 아니기 때문에 유용한 방법으로 무엇인가를 명확히하지 못했습니다. 그렇다고해도 요구 사항을 처리하는 데 성공했다고 가정해도 여전히 효율적인 솔루션은 아닙니다. O (N^2)가 수용 가능하더라도, 불필요하게 새로운 객체를 할당하는 것은 아닙니다. 문자를 제거 할 때마다 새 문자열 인스턴스를 생성하는 대신 s2에 대해 StringBuilder를 사용하십시오. –

0

c3의 세 번째 배열을 만들 수 있습니다. c2에서 제거하지 않을 문자를 추가 할 수 있습니다.

Replace을 사용할 수도 있습니다.

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

원래 O (N^2) 방식은 낭비 적이기 때문에. 그리고 나는 다른 두 가지 대답이 실제로 당신이 성취하려는 것처럼 보이는 일을 어떻게 수행하는지 보지 못합니다.

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

는 성능이 중요 할 것 같지 않다 짧은 문자열을, 부여 : 나는, O (N) 성능을 가지고 당신을 위해 잘 작동이 예를 바랍니다. 하지만 IMHO는 대안보다 이해하기도 쉽습니다.

편집 : 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

이것은 문자 순서를 고려하지 않습니다. 그렇습니까? –

+0

순서는? 새 문자열의 문자는 원래 s2 문자열에 표시된 순서와 같습니다. s1 문자열의 문자 순서는 중요하지 않습니다. OP의 예에서 각 문자열은 순서에 관계없이 원래 문자열에서 간단히 제거되므로이 예에서도 s1의 문자 순서를 고려하지 않습니다. –

+1

이것은 OP의 문제에 대해 "r"을 반환하지만 그는 "re"가 반환되기를 원한다고 명시합니다. (또한, 'string result = new string (s2.Except (s1) .ToArray());와 같이 작성하는 편이 낫습니다. –