Обработка (2 повышения до n) -1 условия

У меня есть один логичный вопрос. У меня есть коллекция объектов сотрудников. Есть 3 условия критериев фильтра, которые имеют дескриптор, например. Имя сотрудника, название офиса, зарплата.

Теперь эти критерии фильтра должны совпадать, например (имя сотрудника И/ИЛИ название офиса И/ИЛИ зарплата)

Так что здесь я должен написать (2 поднять n) -1, если условия справиться с этой ситуацией.

Есть ли другой способ сделать это. Для условия (имя сотрудника И/ИЛИ название офиса) я делаю следующее

if (criteria.EmpName != "" && criteria.OfficeName != "")
    {  
      if (emp.EmpName == criteria.EmpName && emp.OfficeName == criteria.OfficeName) 
        {
              bIsMatch = true;
         }
    }
    else
    {
          if (criteria.EmpName != "" && emp.EmpName == criteria.EmpName)
             bIsMatch = true;
          else if (criteria.OfficeName != "" && emp.OfficeName == criteria.OfficeName)
            bIsMatch = true;
    }

Теперь, если мне нужно справиться с Сарали, я также должен написать минимум 5 условий.

Есть ли другой способ сделать это?


person Tanaji Kamble    schedule 10.11.2010    source источник
comment
2 поднять n можно записать как 2^n   -  person    schedule 10.11.2010
comment
Я серьезно сомневаюсь, что вы одновременно программируете на C#, Java и C++. Почему ты врешь?   -  person GManNickG    schedule 10.11.2010
comment
Я работаю на С#. Но этот вопрос более логичен, чем конкретный язык.   -  person Tanaji Kamble    schedule 10.11.2010
comment
Тогда вы не должны помечать его каким-либо языковым тегом, вы должны пометить его как language-agnostic. Однако я думаю, что ваш код достаточно специфичен для С#, поэтому его следует помечать только тегом C#.   -  person Billy ONeal    schedule 10.11.2010


Ответы (7)


Вы можете объединить свои условия фильтрации и иметь один оператор, который кодирует все параметры:

if( (criteria.EmpName.equals("") || criteria.EmpName.equals(emp.EmpName))
    && (criteria.OfficeName.equals("") || criteria.OfficeName.equals(emp.OfficeName))
    && (criteria.Salary.equals("") || criteria.Salary.equals(emp.Salary)))

В каждом из выражений, объединенных по И, сначала проверяется, пуст ли фильтр, если это так, то эта часть приведет к true, если нет, то проверка выполняется против соответствующего значения в emp и true только тогда, когда эта проверка true .

person Mark Elliot    schedule 10.11.2010
comment
Спасибо, Марк. Я думаю, что это лучшее и идеальное решение. Таким образом, мне не нужно добавлять несколько условий if. Это не просто понять, но вы очень хорошо объяснили. - person Tanaji Kamble; 10.11.2010

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

bool bIsMatch = true;
if (criteria.EmpName != "" && criteria.EmpName != emp.EmpName) {
    bIsMatch = false;
} else if (criteria.OfficeName != "" && criteria.OffIceName != emp.OfficeName) {
    bIsMatch = false;
} /* Repeat for as many conditions as there are */

if (bIsMatch) {
    /* None of the checks above failed */
}
person hobbs    schedule 10.11.2010
comment
Я думаю, что это лучший способ, потому что его легче всего понять и поддерживать. - person John Dibling; 10.11.2010
comment
Вы также можете закоротить и немедленно вернуться, когда обнаружите ложное if, вам не нужно возвращать false, если ни одно из условий не проверено. - person John Dibling; 10.11.2010
comment
@devPro да, это так. Тщательно проследите его и покажите мне, где он может пойти не так. - person hobbs; 10.11.2010

Начните с предположения, что у вас есть совпадение, а затем примените каждый критерий один за другим.

bIsMatch = true;

if (bIsMatch && criteria.EmpName    != "") bIsMatch = emp.EmpName    == criteria.EmpName;
if (bIsMatch && criteria.OfficeName != "") bIsMatch = emp.OfficeName == criteria.OfficeName;
// ...

Или напишите вспомогательную функцию, которая выполняет сопоставление.

bool IsMatch(String criterion, String value)
{
    return criterion == "" || criterion == value;
}

Затем вы можете сделать все в одном большом операторе if:

if (IsMatch(criteria.EmpName,    emp.EmpName)    &&
    IsMatch(criteria.OfficeName, emp.OfficeName) &&
    ...
   )
person John Kugelman    schedule 10.11.2010

Вы можете проверять критерии по отдельности и вести подсчет совпадений. Таким образом, вам нужны только n условия:

int matches = 0;

if (criteria.EmpName != "" && emp.EmpName == criteria.EmpName)
  matches++;
// similar code for other criteria

if (matches >= 2) { // as many matches as required
  // succeeded
}
person casablanca    schedule 10.11.2010
comment
Подобно ответу Хоббса, но на самом деле вы получаете то, что были какие-то несовпадения, а не сколько. - person John Dibling; 10.11.2010

Как насчет этого? Идея хорошо масштабируется для большего количества фильтров, за исключением того, что само сопоставление основано на соглашении (имя – имя).

var map = new Dictionary<string, string>
              {
                { criteria.EmpName, emp.EmpName },       
                { criteria.OfficeName, emp.OfficeName},
                { criteria.ThirdProp, emp.ThirdProp }
              };

bIsMatch = dict.All(kvp => string.IsNullOrEmpty(kvp.Key) || kvp.Key == kvp.Value);

Я бы поставил под сомнение общий дизайн; есть что-то, что кажется неправильным. Как бы вы поступили с полем Salary, которое вы упомянули? Это точно не string? Какое дозорное значение используется в этом случае?

person Ani    schedule 10.11.2010
comment
зарплата будет целой. Пользователь может искать имя сотрудника, начинающееся с Emp1, название офиса ABC, зарплата › 10000 - person Tanaji Kamble; 10.11.2010

Прежде чем писать код, убедитесь, что вы достаточно ясно представляете бизнес-логику. Согласно вашему коду, я вижу, что вы хотите проверить, имеют ли emp и criteria одинаковые EmployeeName и OfficeName, любое из свойств считается одинаковым, если оно string.Empty. Код будет совершенно ясен после того, как вы сами станете ясны. Вот так:

public static bool EmptyOrEquals(this string one, string another)
{
    return string.IsNullOrEmpty(another) || one.Equals(another);
}
bIsMatch = emp.EmpName.EmptyOrEquals(criteria.EmpName) 
            && emp.OfficeName.EmptyOrEquals(criteria.OfficeName);
person Cheng Chen    schedule 10.11.2010

Протестируйте каждый вопрос по отдельности и используйте набор битов для кодирования комбинаций ответов.

Это приводит к более чистому коду, потому что вы тестируете каждый критерий только один раз, он компактен, но удобочитаем, и вы можете легко подключить код для обработки каждой комбинации. И это тоже быстро. O(n) для проверки всех критериев и O(1) для поиска реальной комбинации.

Для небольшого, фиксированного количества критериев вы можете перемещать биты вручную. Для многих критериев или для масштабируемого решения используйте java.util.BitSet.

Пример битового нажатия:

int bits = 0;

if (...criteria 1...) {
    bits = 1;
}

if (...criteria 2...) {
    bits |= 2;
}

if (...bits 3...) {
    bits |= 4;
}

switch (bits) {
case 0: // no criteria matched
    ;
case 1: // criteria 1 matched
    ;
case 2: // criteria 2 matched
    ;
case 3: // criteria 1 AND 2 matched
    ;
case 4: // criteria 3 matched
    ;
case 5: // criteria 1 AND 3 matched
    ;
case 6: // criteria 2 AND 3 matched
    ;
case 7: // criteria 1 AND 2 AND 3 matched
    ;
} 

Вы можете обобщить это решение, используя java.util.BitSet для управления битами для n критериев (полезно, когда n > 64!). Чтобы облегчить быстрый поиск, сохраните хэш каждой комбинации BitSet в карте, которая сопоставляет хэш-код с классом команды.

person Kim Burgaard    schedule 10.11.2010