【问题标题】:Is there a way to shorten the condition if it always compares to the same thing?如果它总是与相同的东西比较,有没有办法缩短条件?
【发布时间】:2012-07-24 19:30:40
【问题描述】:

当我需要编写一个条件来一遍又一遍地比较同一个项目时,我总是觉得很烦人,因为我会多次输入该项目:

string x = textBox1.Text;

if (x == "apple" || x == "orange" || x == "banana" ...)
...

我想要这样的东西(当然这不是正确的语法):

if (x == "apple" || "orange" || "banana" ...)

除了使用字符串数组之外,还有其他解决方案吗?

【问题讨论】:

标签: c#


【解决方案1】:

你的条件是:如果我匹配任何预定义的值,我就是真的。换句话说,如果我是预定义集合的一个元素,它在语义上是 Contains 方法:

if (new [] { "apple", "orange", "banana" }.Contains(x))
{

}

使用数组可以在未来提供更大的灵活性。您可以将其提取、重用、存储、缓存等。当我必须处理超过 2 个已知值时,我总是使用“数组和循环”。

注意:正如 Scott Chamberlain 在 cmets 中指出的那样,使用 HashSet<T>.Contains 大大提高了性能:

var values = new HashSet<string> { "apple", "banana", "orange" };
if (values.Contains(x))
{

}

【讨论】:

  • 在某些情况下(但并非总是如此),值得将数组保存为一个字段并重新使用它,而不是仅仅为了这个用途而创建它。
  • 编译器会优化它,使其与 switch 语句一样高效吗?我的意思是您正在实例化事物,(与其他操作相比,这很慢)
  • @James 效率并不重要。由于数组的大小很小(或者首先这两种方法都不合适),因此无论优化得如何,运行都不会花费很长时间。目的是确定一种可以高效编写且易于理解的方法。
  • 你应该存储它有一个哈希集,而不是一个数组,即使是一些项目,如果它被非常频繁地调用它可能会导致明显的性能差异(我运行了你在我之前发布的确切代码过滤掉流入 XmlStreamReader 的流中的非法字符,从数组切换到 HashSet 大大提高了性能)
  • @ScottChamberlain 对于大约 3 个项目,它根本不重要。如果您要拥有 5 个以上,那么是的,HashSet 会更好。如果您注意到 significant 差异,那么我的猜测是您将哈希集存储在循环之外并在循环内重新创建数组(请参阅我的第一条评论),这将占显着差异。另请注意 HashSet 是毫无意义的,除非在循环之外并重新使用。如果您在内联定义它,那么创建 HashSet 的成本将超过您节省的成本。
【解决方案2】:

扩展方法呢?

public static class Extensions
{
   public static bool IsOneOf<T>(this T input, params T[] possibilites)
   {
      bool result = possibilites.Contains(input);
      return result;
   }
}

然后您可以将代码重写为如下所示:

string input = textBox1.Text;
if(input.IsOneOf("apple", "orange", "banana"))
{
    // ....
}

【讨论】:

  • 应该是string input = textBox1.Text;。否则一个很好的扩展。 +1
  • 这没有描述为什么你验证输入是否是字符串之一。此外,您应该每次都复制所有这些参数。
  • @AvadaKedavra 感谢您的捕获,已修复。
  • @lazyberezovsky 事实上,它没有。但我认为这不是问题,因为该方法是通用的 - 使用它的上下文会告诉您为什么。想想LINQ的Where方法,我觉得这里也一样。
  • @lazyberezovsky 现在我明白你的推理了,尽管我认为这样的包装过于极端。我认为单个 Where 足够简单且具有描述性,可以独立存在,这同样适用于我的 IsOneOf 扩展。
【解决方案3】:

最好的选择(就性能而言)是使用 HashSet

    static HashSet<string> Fruits = new HashSet<string> {"apple", "banana", "orange"};

    string x = textBox1.Text;
    if( Fruits.Contains( x)) {

一旦在 if 条件中超过三个左右的可能性,HashSet 将比直接比较运行得更快。

【讨论】:

  • +1,谢谢!终于有人了解 HashSet 和数组之间的速度差异了。
【解决方案4】:

您可以将重复的代码移到方法中,这也将解释为什么此代码重复 - 因为它验证某物是否是水果。它将增加代码的可读性和可维护性。您还可以重构此逻辑(例如,将其转换为 switch 语句):

private bool IsFruit(string name)
{
   switch(name)
   {
       case "apple":
       case "orange":
       ...
       case "banana":
           return true;
       default:
           return false;
   }
}

用法:

string x = textBox1.Text;
if(IsFruit(x))
   ...

更新:最好不要使用如此复杂的条件 - 有时真的很难理解。您可以使用Introduce Explaining VariableExtract Method(如上)重构以使您的代码更清晰。

【讨论】:

    【解决方案5】:

    使用类似这样的 switch 语句

    switch (x)
    {
       case "apple":
       case "orange":
       case "banana":
          //code
          break;
    }
    

    【讨论】:

      【解决方案6】:

      你可以试试 switch 语句:

      switch (x)
      {
          case "apple":
          case "orange":
          case "banana":
              //...
              break;
      }
      

      【讨论】:

        【解决方案7】:

        您可以使用 switch 语句:

        switch(x)
        {
            case "apple":
            case "orange":
            case "banana":
                // "if" code goes here
                break;
            default:
                // "else" code goes here
                break;
        }
        

        【讨论】:

          【解决方案8】:

          linq 解决方案

          var strarray = new string[]
                  {
                      "apple",
                      "orange",
                      "banana"
                  };
          
          bool a = strarray.Any( x=> x ==  textBox1.Text);
          if(a)
           //CODE 
          else 
           //code
          

          试试这样的开关盒

          Switch(value)
          {
            case "apple":
            case "orange":
            case "banana":....
              //code you want
            break;
          }
          

          【讨论】:

            【解决方案9】:

            我喜欢扩展方法解决方案,并且之前使用过。以下是我的“CommonUtils”库中可用的方法:

                public static bool IsIn<T>(this T toFind, IEnumerable<T> collection)
                {
                    return collection.Contains(toFind);
                }
            
                public static bool IsIn<T>(this T toFind, ICollection<T> collection)
                {
                    return collection.Contains(toFind);
                }
            
                public static bool IsIn<T>(this T toFind, params T[] items)
                {
                    return toFind.IsIn(items.AsEnumerable());
                }
            

            在这三个之间,您几乎可以使用任何集合,也可以将项目指定为参数列表。

            【讨论】:

              【解决方案10】:

              你可以这样做:

              string it = "apple,orange,banana";
              
              if(it.Contains(x))
              {
                //do work
              }
              

              更简单:

              if("apple,orange,banana".Contains(x))
                  {
                    //do work
                  }
              

              【讨论】:

              • 这很危险,像“ban”这样的 x 输入将是正确的。你最好不要多尼格"apple,orange,banana".Split(',').Contains(x)
              • 请解释否决票
              • @James 比拆分更好的是通过添加项目而不是分隔字符串来定义结构。 example
              猜你喜欢
              • 1970-01-01
              • 2020-06-25
              • 1970-01-01
              • 2019-12-01
              • 2011-12-30
              • 1970-01-01
              • 1970-01-01
              • 2019-07-31
              相关资源
              最近更新 更多