删除字符数组中的字符
有没有办法从当前字符数组中删除字符,然后将其保存到新的字符数组中。以下是代码:删除字符数组中的字符
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)
会感谢你的帮助
这不是特别有效,但它可能会是足够快的短字符串:
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倍。
这是非常缓慢的,这个特定的结果可以在O(N)而不是O(N^2)中完成,就像这里一样。所以,不,这似乎不是一个好的答案。 – 2014-10-20 17:22:13
@PeterDuniho如果字符串虽然很小(并且可能比更复杂的实现更快),但这是一个非常好的答案。它非常依赖于要求。它还具有实际实现OP要求的优点。 – 2014-10-21 07:39:12
事实上,OP并没有以有用的方式澄清任何事情,因为他的新解释并不十分清楚。也就是说,即使我们假设你已经成功地解决了他的需求,这仍然不是一个有效的解决方案。即使O(N^2)可以接受,不必要地分配新对象也不会。对于s2使用StringBuilder,而不是每次要删除字符时都生成新的字符串实例。 – 2014-10-21 08:10:01
您可以创建第三个数组c3
,您将在其中添加c2
中不会被删除的字符。您也可以使用Replace
。
string s3 = s2.Replace(s1,"");
最初的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();
这不会考虑字符的顺序,是吗? – 2014-10-20 08:34:58
哪个订单?新字符串中的字符将与原始s2字符串中的顺序相同。 s1字符串中的字符顺序无关紧要。在OP的例子中,每个只是从原始字符串中删除,而不考虑顺序,所以这个例子也不考虑s1中字符的顺序。 – 2014-10-20 08:41:13
事情是这样的,对于OP的问题,这返回“r”,但是他声明他想要“返回”。 (另外,最好把它写成'string result = new string(s2.Except(s1).ToArray());'无论如何。) – 2014-10-20 08:45:03
为什么不直接使用'string'? – 2014-10-20 07:58:49
也许你想'var c3 = s2.Replace(s1,“”).ToCharArray();'但如果你从'remove'中删除'm','o','v'和'e',用'r',因为你会删除两个'e'。也许你应该解释你最终想做什么。 – 2014-10-20 08:00:32
是的,请澄清。你是简单地删除一个子字符串,还是删除remove数组中的所有字符,还是只删除move数组中每个字符的第一个出现? – 2014-10-20 08:13:07