检查变量是否在一个临时值列表中。

73

有没有更简短的方式来表达这个意思:

if(x==1 || x==2 || x==3) // do something

我所需要的是类似于这样的东西:

if(x.in((1,2,3)) // do something

6
如果(x>=1 && x<=3)。 - vcsjones
3
你的方式有什么问题吗?你还有更多的比较吗?因为前一种方式(仅涉及3或4个比较)通常比后一种方式更易读。请注意,“many more”需要更好的上下文才能准确翻译。 - dlev
2
第一个有什么问题吗?它足够简短,自解释,并且效率尽可能高。 - Dave Zych
3
当你使用x == A || x == B || x == C || ... || x == Z这样的语句时,你表达的意思是:"x是否在集合 {A, B, C, ..., Z} 中?" 因此,最清晰的语法应该是 x in {A,B,C, ..., Z}。当条件不同时,应使用||运算符。 - Bakuriu
8个回答

77
你可以通过使用List.Contains方法来实现这一点:
if(new []{1, 2, 3}.Contains(x))
{
    //x is either 1 or 2 or 3
}

我将这个放在同一个类中。 - user1854438
当我运行这个程序时,我得到了“System.Array does not implement Contains”的错误提示。你试图使用存在于System.Collections.Generic中的列表方法来操作一个存在于System中的数组方法。 - J Weezy
在 .Net Core 5.x 中,这种方法似乎不起作用。必须像这样做:int x = 1; if((new List {1, 2, 3}).Contains(x)) {} - Large
1
@JWeezy "Contains"是IEnumerable(例如System.Array)实现的扩展方法。但是,在使用它之前,您必须将“System.Linq”命名空间引入作用域。 - JustALawnGnome7
1
这里唯一可能不同的做法是使用 "stackalloc" 而不是 "new": 这将在堆栈上分配内存,而不是堆上,减少垃圾回收的负担。 - JustALawnGnome7

41
public static bool In<T>(this T x, params T[] set)
{
    return set.Contains(x);
}

...

if (x.In(1, 2, 3)) 
{ ... }

必读资料:MSDN扩展方法


5
甚至可以更新以使用“params”,这样您就可以得到类似于“x.In(1,2,3)”的内容。编辑:当然,在那时,您可以编写“x.In()”,但这有点愚蠢。(另一方面,避免了现有的“IEnumerable <T>”版本,其中您可以传递“x.In(null)”并引发异常) - Chris Sinclair
3
可以更好,你听说过“参数”吗? - It'sNotALie.
2
虽然这绝对是优雅的,但我个人讨厌适用于所有东西的扩展方法。不过还是+1,因为我喜欢优雅 :) - dlev
我一直收到这个错误信息:“扩展方法只能在非泛型非静态类中声明”。 - user1854438
@user1854438: 不,这必须是一个独立的公共类。我已经更新了答案,包括一个链接,应该可以帮助你理解扩展方法。 - Austin Salonen
@dlev: 我基本上同意你的观点。虽然这不是我通常会使用的风格,但它确实满足了楼主的需求。 - Austin Salonen

15
如果它在 IEnumerable<T> 中,使用这个:
if (enumerable.Any(n => n == value)) //whatever

否则,这里有一个简短的扩展方法:

public static bool In<T>(this T value, params T[] input)
{
    return input.Any(n => object.Equals(n, value));
} 

将其放入一个静态类中,您可以像这样使用它:
if (x.In(1,2,3)) //whatever

又是 FGITW!唉。 - It'sNotALie.
我认为你想要 n => object.Equals(n, value),因为 a) 它可以防止 null,并且 b) 确保非值类型也有机会进行值相等性比较。(我认为使用 Contains() 而不是 Any() 也能达到同样的效果。) - dlev
哦,别忘了右括号。 - Isaac

2

2
int x = 1;
if((new List<int> {1, 2, 3}).Contains(x))
{
}

0

我完全是猜测的,如果我错了,请纠正代码:

(new int[]{1,2,3}).IndexOf(x)>-1

-4

你可以创建一个简单的 Dictionary<TKey, TValue> 作为该问题的 决策表

        //Create your decision-table Dictionary
        Action actionToPerform1 = () => Console.WriteLine("The number is okay");
        Action actionToPerform2 = () => Console.WriteLine("The number is not okay");
        var decisionTable = new Dictionary<int, Action>
            {
                {1, actionToPerform1},
                {2, actionToPerform1},
                {3, actionToPerform1},
                {4, actionToPerform2},
                {5, actionToPerform2},
                {6, actionToPerform2}
            };

        //According to the given number, the right *Action* will be called.
        int theNumberToTest = 3;
        decisionTable[theNumberToTest](); //actionToPerform1 will be called in that case.

一旦您初始化了您的Dictionary,剩下要做的就是:

decisionTable[theNumberToTest]();


4
鉴于上下文,这是我见过的超工程最小个体单位之一。 - Grant Thomas
这是最干净和最快的方法之一。这就是你需要执行if条件的全部内容:decisionTable[theNumberToTest](); - Yair Nevet
1
我喜欢看到人们使用O(?)来试图证明某些东西比另一个“更快”。这让我感觉像是新鲜的肉带着一丝薄荷味。 - NPSF3000
如果您只运行测试一次,那么这可能比Contains慢得多——建立字典的时间复杂度为O(n),与建立和扫描列表相同。 - Ryan M
@Ryan Dictionary 只能建立一次。 - Yair Nevet
显示剩余2条评论

-4

以下回答涉及 C# 的可能未来版本 ;-) 如果您考虑切换到 Visual Basic,或者如果微软最终决定将 Select Case 语句引入 C#,它将如下所示:

Select Case X
    Case 1, 2, 3
    ...
End Select

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