C# 替代if,else if
我有很多if,else-if语句,我知道必须有更好的方法来做到这一点,但即使在搜索stackoverflow之后,我也不确定在我的特定情况下如何做到这一点 我正在解析文本文件(账单),并根据账单上是否出现某些字符串,将服务提供商的名称分配给变量(txtvar.provider) 这是我正在做的一个小样本(别笑,我知道这很混乱)。总的来说,大约有300个if,else ifC# 替代if,else if,c#,performance,if-statement,dictionary,loop-unrolling,C#,Performance,If Statement,Dictionary,Loop Unrolling,我有很多if,else-if语句,我知道必须有更好的方法来做到这一点,但即使在搜索stackoverflow之后,我也不确定在我的特定情况下如何做到这一点 我正在解析文本文件(账单),并根据账单上是否出现某些字符串,将服务提供商的名称分配给变量(txtvar.provider) 这是我正在做的一个小样本(别笑,我知道这很混乱)。总的来说,大约有300个if,else if if (txtvar.BillText.IndexOf("SWGAS.COM") > -1) { txtvar
if (txtvar.BillText.IndexOf("SWGAS.COM") > -1)
{
txtvar.Provider = "Southwest Gas";
}
else if (txtvar.BillText.IndexOf("georgiapower.com") > -1)
{
txtvar.Provider = "Georgia Power";
}
else if (txtvar.BillText.IndexOf("City of Austin") > -1)
{
txtvar.Provider = "City of Austin";
}
// And so forth for many different strings
我想使用switch语句这样的语句来提高效率和可读性,但我不确定如何比较BillText。我正在寻找类似的东西,但不知道如何让它工作
switch (txtvar.BillText)
{
case txtvar.BillText.IndexOf("Southwest Gas") > -1:
txtvar.Provider = "Southwest Gas";
break;
case txtvar.BillText.IndexOf("TexasGas.com") > -1:
txtvar.Provider = "Texas Gas";
break;
case txtvar.BillText.IndexOf("Southern") > -1:
txtvar.Provider = "Southern Power & Gas";
break;
}
我绝对愿意接受各种想法
我需要能够确定评估值的顺序。
您可以想象,在分析数百种略有不同的布局时,我偶尔会遇到这样一个问题:对于账单所属的服务提供商,没有一个明确的唯一指标。您想要的是:
完成。一种方法(其他答案显示非常有效的选项):
void Main()
{
字符串输入=“georgiapower.com”;
字符串输出=null;
//字符串数组的数组…元组数组也可以工作,
//或具有任意两个成员类型的列表等。
var search=new[]{
新[]{“SWGAS.COM”,“西南天然气”},
新[]{“georgiapower.com”,“Georgia Power”},
新[]{“奥斯汀市”、“奥斯汀市”}
};
for(int i=0;i-1){
输出=搜索[i][1];
打破
}
}
//(可选)检查是否找到有效的结果。
if(输出==null){
抛出新的InvalidOperationException(“未找到匹配项”);
}
//分配结果、输出结果等。
控制台写入线(输出);
}
这个练习的主要内容是创建一个巨大的
开关
或if/else
结构并不是最好的方法。因为在返回值a之前,您似乎需要搜索键,这是正确的方法,但您需要对其进行循环
// dictionary to hold mappings
Dictionary<string, string> mapping = new Dictionary<string, string>();
// add your mappings here
// loop over the keys
foreach (KeyValuePair<string, string> item in mapping)
{
// return value if key found
if(txtvar.BillText.IndexOf(item.Key) > -1) {
return item.Value;
}
}
//保存映射的字典
字典映射=新字典();
//在此处添加映射
//在钥匙上打圈
foreach(映射中的KeyValuePair项)
{
//如果找到键,则返回值
if(txtvar.BillText.IndexOf(item.Key)>-1){
返回项。值;
}
}
编辑:如果您希望控制元素的求值顺序,请使用,并按求值顺序添加元素。为了避免画师的做法,即在所有键上循环:让我们使用正则表达式
// a dictionary that holds which bill text keyword maps to which provider
static Dictionary<string, string> BillTextToProvider = new Dictionary<string, string> {
{"SWGAS.COM", "Southwest Gas"},
{"georgiapower.com", "Georgia Power"}
// ...
};
// a regex that will match any of the keys of this dictionary
// i.e. any of the bill text keywords
static Regex BillTextRegex = new Regex(
string.Join("|", // to alternate between the keywords
from key in BillTextToProvider.Keys // grab the keywords
select Regex.Escape(key))); // escape any special characters in them
/// If any of the bill text keywords is found, return the corresponding provider.
/// Otherwise, return null.
string GetProvider(string billText)
{
var match = BillTextRegex.Match(billText);
if (match.Success)
// the Value of the match will be the found substring
return BillTextToProvider[match.Value];
else return null;
}
// Your original code now reduces to:
var provider = GetProvider(txtvar.BillText);
// the if is be unnecessary if txtvar.Provider should be null in case it can't be
// determined
if (provider != null)
txtvar.Provider = provider;
//保存哪个账单文本关键字映射到哪个提供者的字典
静态字典BillTextToProvider=新字典{
{“SWGAS.COM”,“西南天然气”},
{“georgiapower.com”,“格鲁吉亚电力”}
// ...
};
//将匹配此词典的任何键的正则表达式
//即任何账单文本关键字
静态正则表达式BillTextRegex=新正则表达式(
string.Join(“|”),//在关键字之间交替
从BillTextToProvider.Keys//获取关键字
选择Regex.Escape(key));//转义其中的任何特殊字符
///如果找到任何帐单文本关键字,请返回相应的提供程序。
///否则,返回null。
字符串GetProvider(字符串billText)
{
var match=BillTextRegex.match(billText);
如果(匹配成功)
//匹配的值将是找到的子字符串
返回BillTextToProvider[match.Value];
否则返回null;
}
//您的原始代码现在减少为:
var provider=GetProvider(txtvar.BillText);
//如果txtvar.Provider不能为空,则if是不必要的
//坚定的
if(提供程序!=null)
txtvar.Provider=提供程序;
对读者来说,使其不区分大小写是一个微不足道的练习
综上所述,这甚至没有假装要对要首先查找的关键字施加顺序-它将找到字符串中最早的匹配项。(然后是在RE中首先出现的一个。)但是你提到你在搜索大型文本;如果.NET的重新实现是好的,那么它的性能应该比200个简单的字符串搜索要好得多。(只对字符串进行一次传递,或者在编译的RE中合并一些常用前缀。)
如果排序对你很重要,你可能需要考虑寻找一个比.NET使用更好的字符串搜索算法的实现。(就像Boyer Moore的变体。)
为什么不使用C#提供的一切?以下匿名类型、集合初始值设定项、隐式类型变量和lambda语法LINQ的使用简洁、直观,并维护了您修改后的模式评估顺序要求:var providerMap = new[] {
new { Pattern = "SWGAS.COM" , Name = "Southwest Gas" },
new { Pattern = "georgiapower.com", Name = "Georgia Power" },
// More specific first
new { Pattern = "City of Austin" , Name = "City of Austin" },
// Then more general
new { Pattern = "Austin" , Name = "Austin Electric Company" }
// And for everything else:
new { Pattern = String.Empty , Name = "Unknown" }
};
txtVar.Provider = providerMap.First(p => txtVar.BillText.IndexOf(p.Pattern) > -1).Name;
更有可能的是,模式对来自可配置的源,例如:
var providerMap =
System.IO.File.ReadLines(@"C:\some\folder\providers.psv")
.Select(line => line.Split('|'))
.Select(parts => new { Pattern = parts[0], Name = parts[1] }).ToList();
最后,@millimoose指出,匿名类型在方法之间传递时不太有用。在这种情况下,我们可以定义一个简单的提供程序类,并对几乎相同的语法使用对象初始值设定项:
class Provider {
public string Pattern { get; set; }
public string Name { get; set; }
}
var providerMap =
System.IO.File.ReadLines(@"C:\some\folder\providers.psv")
.Select(line => line.Split('|'))
.Select(parts => new Provider() { Pattern = parts[0], Name = parts[1] }).ToList();
又一个使用LINQ和字典
var mapping = new Dictionary<string, string>()
{
{ "SWGAS.COM", "Southwest Gas" },
{ "georgiapower.com", "Georgia Power" }
.
.
};
return mapping.Where(pair => txtvar.BillText.IndexOf(pair.Key) > -1)
.Select(pair => pair.Value)
.FirstOrDefault();
如果我们认为字典中包含相似的字符串,则按顺序添加一个顺序,按字母顺序,最短的关键字将是第一个,这将在SCEC
之前选择“SCE”。
return mapping.Where(pair => txtvar.BillText.IndexOf(pair.Key) > -1)
.OrderBy(pair => pair.Key)
.Select(pair => pair.Value)
.FirstOrDefault() ?? "";
有几种方法可以做到这一点,但为了简单起见,可以选择条件运算符:
Func<String, bool> contains=x => {
return txtvar.BillText.IndexOf(x)>-1;
};
txtvar.Provider=
contains("SWGAS.COM")?"Southwest Gas":
contains("georgiapower.com")?"Georgia Power":
contains("City of Austin")?"City of Austin":
// more statements go here
// if none of these matched, txtvar.Provider is assigned to itself
txtvar.Provider;
Func contains=x=>{
返回txtvar.BillText.IndexOf(x)>-1;
};
txtvar.Provider=
包含(“SWGAS.COM”)?“西南天然气”:
包含(“georgiapower.com”)?“格鲁吉亚
var mapping = new Dictionary<string, string>()
{
{ "SWGAS.COM", "Southwest Gas" },
{ "georgiapower.com", "Georgia Power" }
.
.
};
return mapping.Where(pair => txtvar.BillText.IndexOf(pair.Key) > -1)
.Select(pair => pair.Value)
.FirstOrDefault();
return mapping.Where(pair => txtvar.BillText.IndexOf(pair.Key) > -1)
.Select(pair => pair.Value)
.FirstOrDefault() ?? "";
return mapping.Where(pair => txtvar.BillText.IndexOf(pair.Key) > -1)
.OrderBy(pair => pair.Key)
.Select(pair => pair.Value)
.FirstOrDefault() ?? "";
Func<String, bool> contains=x => {
return txtvar.BillText.IndexOf(x)>-1;
};
txtvar.Provider=
contains("SWGAS.COM")?"Southwest Gas":
contains("georgiapower.com")?"Georgia Power":
contains("City of Austin")?"City of Austin":
// more statements go here
// if none of these matched, txtvar.Provider is assigned to itself
txtvar.Provider;
Dictionary<string, string> textValue = new Dictionary<string, string>();
foreach (KeyValuePair<string, string> textKey in textValue)
{
if(txtvar.BillText.IndexOf(textKey.Key) > -1)
return textKey.Value;
}