/ * 编辑:请注意,此代码是一个示例,我的问题通常与(C#)编码有关,因为我经常发现自己处于循环访问的情况,并且根本不需要检查if - 声明。 * /
我怀疑这是否可行,但我想确切地知道。
我有一个作业,我必须读取文件并使用变量。 这些项目位于一行中的逗号文件中,以逗号分隔。我得到的文件的项目间隔为\ t,有时还有空格。 一个例子:" \ t波音737-800" (注意两个空格)
这是我为摆脱标签(和空格)所做的功能:
private string RemoveTab (string text)
{
string tempText = "";
foreach (char c in text)
{
if (c == ' ' && tempText == "")
{
//nothing has to be done
}
else if (c != '\t')
{
tempText += c;
}
}
return tempText;
}
现在回答真正的问题: 一旦跳过所有选项卡和空格,就不再需要检查任何内容。尤其不是第一个if语句。有没有办法可以禁用第一个if语句?
在这个例子中,我怀疑它对性能有任何重大影响。嗯,我知道它没有。但是由于我的i5-4570在Overwatch和Battlefield 4等游戏中遇到了麻烦,我希望尽可能提高效率。我认为在没有可能满足要求的情况下检查很多东西可能会对CPU密集型应用程序中的CPU使用率产生一些影响。
答案 0 :(得分:3)
不要重新发明轮子。要删除起始和尾随空格,请使用string.Trim(' ')
(或等效的string.TrimStart
和string.TrimEnd
(如果适用)。
其余的,可以使用LINQ完成:
var noTabsString = new string(text.Trim(' ').Where(c => c != '\t').ToArray());
使用字符串连接来构建任意长字符串通常不是一个好主意,您应该在任何情况下使用StringBuilder
。
但是,我还不能回避你的方法;利用string
实现IEnumerable<char>
的事实,并在您过滤掉所有不需要的字符后,实例化一个string
。
更新回答您的具体问题,如果不再需要,则无法在循环内停用if
条件。你唯一可以做的就是将循环分成两部分,但我真的不建议这样做,除非你检查的条件被证明是一个不可接受的瓶颈。
一种方法是使用以下模式:
using (var enumerator = sequence.GetEnumerator())
{
while (enumerator.MoveNext())
{
if (veryExpensiveCheck) { ... }
else if (cheapCheck)
{
...
break; //veryExpensiveCheck not needed anymore.
}
}
while (enumerator.MoveNext())
{
if (cheapCheck) { ... }
}
}
可读性有所下降,所以,除非真的有必要,否则不要这样做,并且你有经验数据证明第一种选择是不可接受的。
答案 1 :(得分:1)
一旦跳过所有选项卡和空格,就不再需要检查任何内容了。
值得注意的是,您所拥有的代码仅在初始部分中跳过空格,但在任何地方都会标记。目前尚不清楚您是否想要这里或您在此描述的内容。我将假设你的代码在结果方面是正确的。
这是一个很常见的模式,你想为循环的一部分做一些事情,而其余部分做其他事情。通过从foreach
中删除语法糖很容易做到:
foreach (char c in text)
{
if (c == ' ' && tempText == "")
{
//nothing has to be done
}
else if (c != '\t')
{
tempText += c;
}
}
变为:
using(var en = text.GetEnumerator())
{
while (en.MoveNext())
{
char c = en.Current;
if (c == ' ' && tempText == "")
{
//nothing has to be done
}
else if (c != '\t')
{
tempText += c;
}
}
}
现在我们已经分解了foreach
,我们可以更轻松地进行更改。
using(var en = text.GetEnumerator())
{
while (en.MoveNext())
{
char c = en.Current;
if (c != ' ')
{
do
{
if (c != '\t')
{
tempText += c;
}
} while (en.MoveNext());
return tempText;
}
}
return ""; // only hit if text was all-spaces
}
现在我们只是检查c
是否是空格,直到它第一次找到非空格并为枚举的其余部分执行不同类型的循环。 (如果您只想在开始时跳过制表符,则将其从内循环中取出并进行初始测试c != ' ' && c != '\t'
)。
(这值得多少是另一个问题。我发现类似于此的更改可以产生明显的改进,但是除非输入字符串非常大或代码经常受到影响,否则它不会重要的是 - 对于在更广泛的应用背景下本身并不明显的事物的明显改变,并不是在更广泛的背景下的明显改变。)
这是适用于任何foreach
的一般情况。虽然我们可以做两件事。
一个是我们可以删除using
因为我们知道字符串的枚举器在Dispose()
中没有做任何事情。只有你真的确定你可以。
另一个是我们可以从foreach
更改为迭代。考虑一下我们也可以将原始逻辑编写为:
for(int i = 0; i < text.Length; ++i)
{
char c = text[i]; // We could also have done char[c] arr = text.Chars and used that. The compiler does the equivalent.
if (c == ' ' && tempText == "")
{
//nothing has to be done
}
else if (c != '\t')
{
tempText += c;
}
}
从这个起点我们可以做到:
for(int i = 0; i < text.Length; ++i)
{
char c = text[i];
if (c != ' ')
{
do
{
c = text[i];
if (c != '\t')
{
tempText += c;
}
} while(++i < text.Length);
return tempText;
}
return "";
}
或者:
int i = 0
while(i < text.Length)
{
char c = text[i];
if (c != ' ')
{
break;
}
++i;
}
while(i < text.Length)
{
char c = text[i];
if (c != '\t')
{
tempText += c;
}
++i;
}
这两种模式都使用索引而不是foreach
来执行两个半循环。很多人发现这个更简单,在某些情况下性能更高(特别是对于数组和字符串[请注意,编译器将数组或字符串类型的变量上的foreach
转换为规范MoveNext()/Current
组合但是进入幕后的索引for(;;)
,你不想失去那个优化])虽然不是一般的(它不适用于无法编入索引的IEnumerable<char>
。
答案 2 :(得分:0)
您可以采用首先如果应该始终为假的方式进行条件检查。
if (!(c == ' ' && tempText == "") && (c != '\t')){
tempText += c;
}
希望这有帮助。
答案 3 :(得分:0)
您可以考虑用一个Action<>
对象替换循环体,该对象封装了所需的功能,并且可以在运行时更改。
private string RemoveTab(string text)
{
string tempText = String.Empty;
// An Action is an object that encapsulates a method that does
// not return a value. If you need to return something, use a Func<>.
// Create an Action<> that will be used in the loop until the initial
// condition has ceased. This Action<> will replace itself with the
// subsequent Action<>.
Action<char> Process = new Action<char>(c =>
{
if ((c != ' ') && (c != '\t'))
{
tempText += c;
// Replace the Action with new functionality for subsequent
// iterations of the loop.
Process = new Action<char>(c1 =>
{
if (c1 != '\t')
{
tempText += c1;
}
});
}
});
// Now the loop will use the Process Action<>, which will change
// itself to new behaviour once the initial condition no longer holds.
foreach (char c in text)
{
Process(c);
}
return tempText;
}
我不推荐这种方法来处理一个简单的问题,例如你在问题中使用的问题,但对于更复杂的情况,可能值得考虑。但是,请始终考虑将来可能需要修改代码,如果您太聪明,可能会感到非常高兴。