C# 替代if,else if

C# 替代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,else-if语句,我知道必须有更好的方法来做到这一点,但即使在搜索stackoverflow之后,我也不确定在我的特定情况下如何做到这一点

我正在解析文本文件(账单),并根据账单上是否出现某些字符串,将服务提供商的名称分配给变量(txtvar.provider)

这是我正在做的一个小样本(别笑,我知道这很混乱)。总的来说,大约有300个if,else if

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;

}