if语句匹配多个值


77

还有什么更简单的方法来编写此if语句?

if (value==1 || value==2)

例如...在SQL中,您可以说 where value in (1,2)而不是where value=1 or value=2

我正在寻找适用于任何基本类型的东西...字符串,整数等。


2
轻松是个人喜好。就个人而言,我认为没有比这更容易的事情了value == 1 || value == 2
乔尔·埃瑟顿

1
@Joel:这很容易,但是对于习惯说“我希望它是1或2”的人来说却不直观。事实证明,确实有一些语言实现了这种语法。IBI的FOCUS查询lanaguage,仅此一项。
史蒂文·苏迪特

@Steven Sudit-在这种情况下,“直觉”归结为个人喜好。
乔尔·埃瑟顿

@Steven Sudit-我必须承认,到目前为止,我对某些荒谬的长度感到很开心,其中一些答案只是为了解决一个简单的问题。
乔尔·埃瑟顿

5
这只是复杂得多的基本示例。我不仅在处理2个值。我还试图使其中一些行更易于阅读。在某些情况下,我的if语句跨度过大,并且具有数十种可能的值和长变量名。
里奇(Ricky)

Answers:


147

怎么样:

if (new[] {1, 2}.Contains(value))

虽然这是一个hack :)

或者,如果您不介意创建自己的扩展方法,则可以创建以下内容:

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

您可以像这样使用它:

if (1.In(1, 2))

:)


11
我认为第一个建议并不是真正的hack,对我来说似乎很优雅,尤其是如果它是大多数人都在后台调用的代码IsOneOfACertainType(typeToCheck);
Coops,2013年

8
不要忘记using System.Linq;使用Contains
Guilherme de Jesus Santos

2
真的看起来像Python!
Panzercrisis'Aug

36

一种更复杂的方法:)模拟SQL的'IN':

public static class Ext {    
    public static bool In<T>(this T t,params T[] values){
        foreach (T value in values) {
            if (t.Equals(value)) {
                return true;
            }
        }
        return false;
    }
}

if (value.In(1,2)) {
    // ...
}

但是采用标准方式,它更具可读性。

编辑:根据@Kobi的建议,一个更好的解决方案:

public static class Ext {    
    public static bool In<T>(this T t,params T[] values){
        return values.Contains(t);
    }
}

需要返回类型,但是扩展方法也是我要建议的内容
Daniel DiPaolo 2010年

+1。就像我的一样,这是不错的解决方案,但是您可以使用泛型。我会与你:)替代矿
goenning

我真的很喜欢这个版本。我认为可能必须构建自己的方法。
里奇(Ricky)

7
你不能写return values.Contains(t)吗?还是return values.Any(v => t.Equals(v))
科比2010年

27

这是你想要的 ?

if (new int[] { 1, 2, 3, 4, 5 }.Contains(value))

7

另外,如果将来测试非1或2的值时,这将为您提供更大的灵活性,那就是使用switch语句

switch(value)
{
case 1:
case 2:
   return true;
default:
   return false
}

我什至不说“替代”,这与在示例中给定的列表的IN的SQL使用最相似(例如Contains(),IN与子查询的结果相对应更多)。
乔恩·汉纳

6

如果您有一个List,则可以使用.Contains(yourObject)(如果您只是在寻找它的存在)(例如where)。否则,请查看Linq .Any()扩展方法。


5

使用Linq,

if(new int[] {1, 2}.Contains(value))

但我不得不认为,如果您的原始版本更快。


两者之间的性能差异几乎毫无关系。原件更具可读性和惯用性。当然可以写Enumerable.Range(0, 10).ToList().ForEach(x => Console.WriteLine(x));而不是写,for(int i = 0; i < 10; i++) { Console.WriteLine(i); }但这只会激怒人们。“没有人写信让他们6成为一个团体。”
杰森2010年

@Jason-我同意,如果我看到我在生产代码中写的内容,那我会很生气。与其说是“完全遵循”,不如说是“一行人来解释一种方法”。的确,我同意人们对switch语句的建议。
乔尔·隆多

5

如果在长列表中多次搜索固定值列表中的值,则应使用HashSet <T>。如果列表很短(<〜20个项目),则基于此测试HashSet与List性能的比较,List可能会有更好的 性能

HashSet<int> nums = new HashSet<int> { 1, 2, 3, 4, 5 };
// ....
if (nums.Contains(value))

:)这是一个有趣的声明HashSet...考虑到它是以其数据存储实现命名的,为什么您认为它与BST相关?
阿列克谢·莱文科夫

@AlexeiLevenkov :)感谢您指出这一点。我做了一些搜索,.NET版本的HashSet仅基于线性算法。相比之下,Java 8的HashMap使用的是自平衡BST。
detale


2

这样的扩展方法就可以做到...

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

像这样使用它:

Console.WriteLine(1.In(1,2,3));
Console.WriteLine("a".In("a", "b"));

1

主观更容易,但也许switch语句会更容易?您不必重复该变量,因此该行上可以容纳更多的值,并且具有很多比较的行比使用if语句的行更易读。


1

在vb.net或C#中,我希望将变量与任意数量的单独命名的对象(与例如集合中的所有事物相对)进行比较的最快的通用方法将是简单地将每个对象与比较对象进行比较正如您所做的。当然可以创建一个集合的实例并查看它是否包含该对象,并且这样做可能比单独将该对象与所有项目进行比较更具表现力,但是除非使用编译器可以明确识别的构造,否则此类代码几乎肯定会比仅仅进行单个比较慢得多。如果代码本质上每秒最多可以运行数百次,我不会担心速度,但是我会警惕代码被重新用于某些用途。

如果变量类似于枚举类型,则另一种方法是选择2的幂次枚举值以允许使用位掩码。如果枚举类型具有32个或更少的有效值(例如,开始Harry = 1,Ron = 2,Hermione = 4,Ginny = 8,Neville = 16),则可以将它们存储为整数并一次检查一次多个位操作((if(((thisOne&(Harry | Ron | Neville | Beatrix))!= 0)/ *做某事* /。这将允许快速代码,但仅限于具有少量值的枚举。

一种更强大的方法,但是必须谨慎使用的一种方法是,使用值的某些位指示事物的属性,而其他位标识项目。例如,位30可以指示角色是男性,位29可以指示哈利的朋友,等等,而低位则可以区分字符。这种方法将允许添加可能是也可能不是Harry朋友的字符,而不需要更改检查Harry朋友的代码。这样做的一个警告是,必须区分用于设置枚举值的枚举常量和用于测试枚举值的枚举常量。例如,要设置一个变量以指示Harry,可能需要将其设置为0x60000001,但要查看变量是否为Harry,则应使用0x00000001对它进行位测试。

如果可能值的总数适中(例如16-16,000左右),则还有一种方法可能有用,该方法是使与每个值关联的标志数组。然后,可以编写类似“ if((((characterAttributes [theCharacter]&chracterAttribute.Male)!= 0)”的代码。当字符数非常小时,这种方法最有效。如果数组太大,则缓存丢失可能会变慢将代码降低到单独测试少量字符的速度会更快。


1

使用扩展方法:

public static class ObjectExtension
{
    public static bool In(this object obj, params object[] objects)
    {
        if (objects == null || obj == null)
            return false;
        object found = objects.FirstOrDefault(o => o.GetType().Equals(obj.GetType()) && o.Equals(obj));
        return (found != null);
    }
}

现在您可以执行以下操作:

string role= "Admin";
if (role.In("Admin", "Director"))
{ 
    ...
} 

0
public static bool EqualsAny<T>(IEquatable<T> value, params T[] possibleMatches) {
    foreach (T t in possibleMatches) {
        if (value.Equals(t))
            return true;
    }
    return false;
}
public static bool EqualsAny<T>(IEquatable<T> value, IEnumerable<T> possibleMatches) {
    foreach (T t in possibleMatches) {
        if (value.Equals(t))
            return true;
    }
    return false;
}

-1

我遇到了同样的问题,但是用switch语句switch(要打开的值)解决了这个问题。情况2:您要执行的代码;默认值:返回值

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.