хороший способ сделать, если ВСЕ предметы в коллекции проходят тестирование - PullRequest
0 голосов
/ 12 ноября 2010

Я имею в виду следующее:

bool passed = true;
for(int i = 0; i < collection.Length; i++)
{
    if(!PassesTest(collection[i]))
    {
        passed = false;
        break;
    }
}
if(passed){/*passed code*/}

требует дополнительной переменной, дополнительного теста

for(int i = 0; i < collection.Length; i++)
{
    if(!PassesTest(collection[i]))
    {
        return;
    }
}
{/*passed code*/}

аккуратно, но требует, чтобы это было его собственной функцией, если это self внутри циклаили что-то, не самый эффективный способ ведения дел.Кроме того, написание целой дополнительной функции - боль

if(passed){/*passed code*/}
for(int i = 0; i < collection.Length; i++)
{
    if(!PassesTest(collection[i]))
    {
        goto failed;
    }
}
{/*passed code*/}
failed: {}

замечательно, но вы должны разбираться с названиями ярлыков и уродливым синтаксисом ярлыков

for(int i = 0; ; i++)
{
    if(!(i < collection.Length))
    {
         {/*passed code*/}
         break;
    }
    if(!PassesTest(collection[i]))
    {
        break;
    }
}

, вероятно, самый красивый, но все женемного ручной, вроде как тратить функциональность конструкции цикла for, например, вы не можете сделать это с помощью foreach

Какой самый лучший способ решить эту проблему?

кажется,мне что-то вроде этого было бы неплохо: foreach (...) {...} finally {...} // выполняется только в том случае, если цикл заканчивается обычным образом (без прерывания)

я что-то упустил?потому что это очень распространенная проблема для меня, и мне не очень нравятся какие-либо решения, которые я придумаю.

Я использую c ++ и C #, поэтому решения в любом из них были бы хорошими.но также будет заинтересован в решениях на других языках.(хотя принцип дизайна, который избегает этого на любом языке, был бы идеальным)

Ответы [ 7 ]

2 голосов
/ 12 ноября 2010

Если ваш язык не имеет этой функции, напишите функцию «forall», которая принимает два аргумента: список и функцию с логическим значением, которая должна быть истинной для всех элементов списка.Тогда вам нужно всего лишь написать его один раз, и это не имеет большого значения, насколько это идиоматично.

Функция "forall" выглядит точно так же, как ваш второй пример кода, за исключением того, что теперь "collection" и "passTest"Аргументы этой функции.

Вызов forall выглядит примерно так:

if (forall(myList,isGood)) {

, который доступен для чтения.

В качестве дополнительного бонуса, вы можете реализовать «существует», вызвавforall "на отрицательную булеву функцию и отрицание ее ответа.То есть «существует x P (x)» реализовано как «не x, а не P (x)».

2 голосов
/ 12 ноября 2010

Вы можете использовать Linq в .NET.
Вот пример на C #:

if(collection.All(item => PassesTest(item)))
{
    // do my code
}
0 голосов
/ 20 июля 2011

Python (начиная с версии 2.5):

if all(PassesTest(c) for c in collection):
    do something

Примечания:

  • мы можем выполнять итерацию непосредственно в коллекции, нет необходимости в индексе и поиске
  • все () и любые () встроенные функции были добавлены в Python 2.5
  • аргумент any(), т.е. PassesTest(c) for c in collection, является генератором выражения . Вы также можете просмотреть его как список , добавив скобки [(PassesTest(c) for c in collection]
  • ... for c in collection вызывает итерацию по коллекции (или последовательности / кортежа / списка). Для указания используйте dict.keys(). Для других типов данных используйте правильный метод итератора.
0 голосов
/ 12 ноября 2010

Scala:

def passesTest(i: Int) = i < 5 // example, would likely be idiomatically in-line
var seq = List(1,2,3,4);
seq.forall(passesTest) // => True

Большинство, если не все ответы, представленные здесь, говорят: конструкции более высокого порядка - такие как "проходящие функции" - действительно, действительно хороши .Если вы разрабатываете язык, не забывайте о последних 60 с лишним лет языков программирования / дизайна.

0 голосов
/ 12 ноября 2010

Groovy:

if (!collection.find { !PassesTest(it) }) {
  // do something
}
0 голосов
/ 12 ноября 2010

Рубин:

if collection.all? {|n| n.passes_test?}
  # do something
end

Clojure:

(if (every? passes-test? collection)
  ; do something
  )
0 голосов
/ 12 ноября 2010

C ++ и STL

if (std::all_of(collection.begin(), collection.end(), PassesTest))
{
    /* passed code */
}
...