如何在条件语句中组合 || 运算符

77

取代

if (foo == "1" || foo == "5" || foo == "9" ... ) 

我喜欢将它们组合在一起,类似于以下方式(但不起作用):

if (foo == ("1" || "5" || "9" ... ))

那有可能吗?


1
作为相关的附带说明,Perl 6 应该有这些 (if (foo == any(1, 5, 9))),而 Perl 5 代码也可以使用 CPAN 模块 http://search.cpan.org/perldoc?Quantum%3A%3ASuperpositions 或 http://search.cpan.org/perldoc?Perl6%3A%3AJunction 来使用它们。这些 any() 和 all() 函数被称为“junctions”,我很喜欢这个想法 :) - Sundar R
4
另外一点需要注意的是,Python 使用 foo in ("1", "5", "9") 这种语法,我认为这样更加清晰明了。如果 C# 有一种简洁的数组字面量语法,那么类似的语法可能是 ["1", "5", "9"].index(foo) != -1 - tobyodavies
不适用于所有情况,所以我不会将其发布为答案,但对于您的特定示例:if (int.Parse(foo) % 4 == 1) 将作为一个好的简单一行代码解决问题。在这种情况下假设 foo 总是可以解析为单个数字的整数。由于不知道您的预期用例,因此无法确定是否符合您的需求。 - Darrel Hoffman
在PERL中,你实际上不需要任何函数,你只需使用正则表达式 if(foo=~/^(1|5|9)$/) 即可。 - Naryl
2
如果您不需要值,则使用set()通常比始终为1的dict()更好。 - Lie Ryan
显示剩余12条评论
8个回答

170

很遗憾,你最好的选择是创建一个扩展方法。

public static bool IsOneOf<T>(this T value, params T[] options)
{
    return options.Contains(value);
}

你可以这样使用它:

if (foo.IsOneOf("1", "5", "9"))
{
    ...
}

通用类型可以用于任何类型(int、string等)。


5
如果我今天还有更多的点赞次数,我会给你一个+1的朋友。好的,聪明的解决方案。 - Mike Perrenoud
6
这是所有答案中最清洁、最可重复使用的。 - Zbigniew
1
这里有更多的内容:https://dev59.com/G3VC5IYBdhLWcg3whBaj - Tomasito
1
OP问题中的||运算符是一个快捷操作符。Contains扩展方法是否在找到匹配项后立即退出?还是会遍历整个数组?如果不是,这比switch..case更可取,因为您可以使用非常量表达式。 - Boluc Papuccuoglu
1
除非在编译时进行了优化(例如如果所有值都是常量),否则创建 params T[] 数组始终是 O(N),因此它不一定会从短路中受益。 - Lie Ryan
显示剩余5条评论

37

你不能用这种方式做。相反,你可以这样做:

string[] validValues = new string[] { "1", "5", "9", "whatever" };
if(validValues.Contains(foo))
{
    // do something
}

4
我不确定,但似乎有人遍历并对每个人的投票进行了负面评价,除了@Gray。 - Mike Perrenoud
不是我,我保证。我会去点赞所有的内容。 - Gray
2
不是我,我也不明白为什么我的问题被投了两次反对票。 - KMC
5
有些人(不是我!)可能认为这很基础,或者可以通过Google或其他网站上的内容得到答案。或者有人只是个混蛋。或两者都有可能。我给你点了一个赞来消除负面影响。看那个匿名混蛋怎么办! - thumbtackthief
嗯,我肯定没想到这个答案会得到+24的赞,事实上它相当简单。另一方面,我的大多数最受欢迎的答案基本上都是基础知识。谢谢! - Zbigniew
显示剩余2条评论

25

有一个可能的选择:

switch (foo)
{
    case "1":
    case "5":
    case "9":
        // your code here

        break;
}

另一个可能的选择是这个:

var vals = new string[] { "1", "5", "9" };
if (vals.Contains(foo))
{
    // your code here
}

我认为这是更多的代码,即 foo = 1 || foo = 2 ....... - Trikaldarshiii
@mohit,第二个选项不会是因为你只需要在类中声明一次数组。但是,是的,我已经等待了十年这个语法增强。 - Mike Perrenoud
你是否考虑过看看我的方法,难道你不认为它比任何给出的答案都更好吗? - Trikaldarshiii

23
如果所有选项都只有一个字符,您可以这样做:
if ("159".IndexOf(foo) != -1)
{
  //do something
}

1
嗯,有趣的方法。我从未考虑过。不错。 - Mike Perrenoud
13
读起来就不那么容易了…… - RedX
4
@user902383 是的,我知道,这就是为什么我在我的回答顶部写道:“如果所有选项都只有一个字符”。 - jsedano
@RedX 我非常注重可读性,这就是为什么我认为Trevor Pilley的答案是最好的,这个 foo.IsOneOf("1", "5", "9") 真的棒极了,我认为我的回答可能会根据上下文而降低可读性。 - jsedano

18

这里还有另一个选择:

bool x = new[] { "1", "5", "9" }.Any(a => a == "5"); //x == true
bool y = new[] { "1", "5", "9" }.Any(a => a == "8"); //y == false

在这种情况下最好使用 .Contains(foo),因为 lambda 的灵活性在这里浪费了。如果有需要执行的复杂表达式,则 Any 将更加有用。


1
我更喜欢使用.Contains(val)而不是.Any(x => x == val) - fjdumont
我能理解。我认为,对于这种类型的集合而言,除了语法之外,它没有任何差别,但是对于某些集合,比如说二叉查找树,.Contains会执行二分查找... 而 .Any 仍然需要 O(n) 的时间进行查找。 - Gray
这将非常棒,不是吗?如果我没记错的话,二叉搜索树的搜索时间复杂度为O(log n)。 - fjdumont
对的,这就是我说的。虽然如此,这次讨论很有帮助。我学到了使用Any而不是Contains的真正原因。除非你需要一个特定的lambda表达式(在我的情况下不需要),否则你只会真正地使用Any()而不是Contains。除非你需要检查的东西比值相等更复杂,否则Contains()更好(最坏的情况:与Any相同)。我会把我的答案留在这里,以备将来参考。 - Gray

13

如果这对你可行,你可以这样做:

if ( (new string[] {"1","9","5","6" }).Contains(foo))
{

}

1
每次运行这个程序,它都会分配一个新的数组吗? - Samuel Edwin Ward
@SamuelEdwinWard:看起来应该没问题。我不知道当前的运行时是否这样做,但是对于这一行的逃逸分析应该允许立即释放新数组。 - Zan Lynx
1
你可以省略string,编译器会根据指定的数组值自动推断出来。 - Sandor Drieënhuizen
2
@SamuelEdwinWard - 是的,每次执行代码块时它都会分配并填充一个新数组。如果允许值列表在编译时被定义,并且在应用程序的生命周期内基本上是“静态”的,那么您可以将其定义为const或static字段,这将减少方法的GC开销,如果它经常被调用的话。 - Trevor Pilley

9
您可以使用 switch 语句:
switch (foo) {
    case "1":
    case "5":
    case "9":
        // ...
        break;
    case "2":
    case "4":
        // ...
        break;
}

如果foo是一个字符串,请注意大小写敏感性。

9
如果您有多个if条件,建议考虑使用switch语句,因为编译器会在可能的情况下创建跳转表以提高速度。可以查看这里进行速度测试。需要注意的是,如果条件数量足够大以涵盖开销,C#编译器还将创建HashTable对象。
因此,这是一种更好的方法,
switch (foo) {
case "1":
case "5":
case "9":
    // ...
    break;
case "2":
case "4":
    // ...
    break;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接