если операторы соответствуют нескольким значениям - PullRequest
71 голосов
/ 11 октября 2010

Есть ли более простой способ написать это, если заявление?

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

Например ... в SQL вы можете сказать where value in (1,2) вместо where value=1 or value=2.

Я ищу что-то, что могло бы работать с любым базовым типом ... string, int и т. Д.

Ответы [ 14 ]

122 голосов
/ 11 октября 2010

Как насчет:

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

Хотя это хак:)

Или, если вы не против создать свой собственный метод расширения, вы можете создать следующее:

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

И вы можете использовать его так:

if (1.In(1, 2))

:)

35 голосов
/ 11 октября 2010

Более сложный способ :), который эмулирует 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);
    }
}
24 голосов
/ 11 октября 2010

Это то, что вы ищете?

if (new int[] { 1, 2, 3, 4, 5 }.Contains(value))
6 голосов
/ 11 октября 2010

В качестве альтернативы, и это даст вам больше гибкости, если в будущем при проверке значений, отличных от 1 или 2, будет использоваться оператор переключения

switch(value)
{
case 1:
case 2:
   return true;
default:
   return false
}
6 голосов
/ 11 октября 2010

Если у вас есть список, вы можете использовать .Contains (yourObject), если вы просто ищете его существующим (например, где).В противном случае посмотрите на метод расширения Linq .Any ().

5 голосов
/ 14 февраля 2014

Если вы ищете значение в фиксированном списке значений много раз в длинном списке, следует использовать HashSet . Если список очень короткий ( HashSet против производительности списка

HashSet<int> nums = new HashSet<int> { 1, 2, 3, 4, 5 };
// ....
if (nums.Contains(value))
5 голосов
/ 11 октября 2010

Используя Linq,

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

Но я бы подумал, что ваш оригинал, если быстрее.

3 голосов
/ 11 октября 2010

Как правило, нет.

Да, есть случаи, когда список находится в Array или List, но это не общий случай.

1 голос
/ 11 октября 2010

В vb.net или C # я ожидал бы, что самый быстрый общий подход для сравнения переменной с любым разумным количеством объектов с индивидуальным именем (в отличие, например, от всех вещей в коллекции) будет состоять в простом сравнении каждого объекта с сравните многое, как вы сделали. Конечно, можно создать экземпляр коллекции и посмотреть, содержит ли он объект, и это может быть более выразительным, чем сравнение объекта со всеми элементами по отдельности, но если только не используется конструкция, которую компилятор может явно распознать, такой код почти наверняка будет намного медленнее, чем просто делать отдельные сравнения. Я не стал бы беспокоиться о скорости, если код по своей природе будет работать не более нескольких сотен раз в секунду, но я бы опасался, что код будет перенаправлен на что-то, что выполняется гораздо чаще, чем предполагалось изначально.

Альтернативный подход, если переменная является чем-то вроде типа перечисления, заключается в выборе значений перечисления со степенью двойки, чтобы разрешить использование битовых масок. Если тип перечисления имеет 32 или менее допустимых значений (например, начиная с Гарри = 1, Рон = 2, Гермиона = 4, Джинни = 8, Невилл = 16), можно сохранить их в целое число и проверить несколько битов одновременно в одном операция ((if ((thisOne & (Harry | Ron | Neville | Beatrix))! = 0) / * Сделайте что-нибудь * /. Это позволит быстро кодировать, но ограничено перечислениями с небольшим количеством значений.

Несколько более мощный подход, но который следует использовать с осторожностью, заключается в использовании некоторых битов значения для указания атрибутов чего-либо, в то время как другие биты идентифицируют элемент. Например, бит 30 может указывать, что символ является мужчиной, бит 29 может указывать на друга Гарри и т. Д., В то время как младшие биты различают символы. Этот подход позволил бы добавлять персонажей, которые могут быть или не быть друзьями Гарри, не требуя изменения кода, проверяющего друга Гарри. Одним из предостережений при выполнении этого является то, что нужно различать константы перечисления, которые используются для установки значения перечисления, и те, которые используются для ТЕСТИРОВАНИЯ его. Например, чтобы установить переменную, указывающую на Гарри, можно задать для нее значение 0x60000001, но, чтобы увидеть, является ли переменная Гарри, нужно проверить ее с помощью 0x00000001.

Еще один подход, который может быть полезен, если общее число возможных значений является умеренным (например, 16-16 000 или около того), должен иметь массив флагов, связанных с каждым значением. Затем можно написать что-то вроде «if (((characterAttributes [theCharacter] & chracterAttribute.Male)! = 0)». Этот подход будет работать лучше всего, когда количество символов довольно мало. Если массив слишком велик, пропадание кэша может замедлиться код до такой степени, что тестирование по небольшому количеству символов по отдельности будет быстрее.

1 голос
/ 11 октября 2010

Метод расширения, подобный этому, сделает это ...

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"));
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...