Оператор «или» без повторения условия левой руки - PullRequest
5 голосов
/ 14 января 2010

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

if x == something or x == somethingelse

Я часто заканчиваю тем, что пишу:

if x == something or somethingelse

Просто из чистого интереса, какие-нибудь языки / языки там поддерживают это?

Ответы [ 8 ]

11 голосов
/ 14 января 2010

Python, вид:

if x in [something, somethingelse]:
    ...

in просто проверяет, присутствует ли элемент в данном списке. Точно так же в Haskell:

if x `elem` [something, somethingelse] then ...

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

6 голосов
/ 14 января 2010

SQL имеет оператор in: x in (something, somethingelse), и существует множество языков, где вы можете реализовать нечто подобное.

Например, в c # я использую собственный метод расширения: if (x.In("something", "somethingelse"))...

edit вот источник моего метода расширения c #:

public static bool In<T>(this T item, params T[] test_values) {
  foreach (T test_value in test_values)
  {
    if (test_value.Equals(item))
    {
      return true;
    }
  }

  return false;
}
3 голосов
/ 14 января 2010

На многих языках программирования вы можете сделать что-то вроде этого:

myArray[something, somethingElse].Contains(x)

... но я думаю, что это будет работать немного хуже.

2 голосов
/ 15 января 2010

Язык программирования Icon прекрасно поддерживает эту идиому. Icon был разработан Ralph Griswold, который уже разработал SNOBOL, и вся его модель оценки основана на успехе или неудаче. Все составляет, и в принципе каждое выражение может дать несколько результатов. Вы можете написать такие вещи как

if x == (something | somethingelse) then write("Goodie!")

Вот модель оценки:

  1. Сначала вы оцениваете выражение в скобках и получаете something
  2. Тогда вы сравниваете something с x
  3. Если они не равны, выражение завершается неудачно , и механизм оценки автоматически возвращается.
  4. Во время обратного отслеживания вычисление выражения в скобках возобновлено , и оно снова успешно! На этот раз он производит somethingelse.
  5. Предположим, это сравнение успешно. Затем вычисляется тело if и программа записывает в стандартный вывод.

Вот еще один интересный сценарий: каждое сравнение либо успешное, либо неудачное, и если оно успешно, оно возвращает свой правый аргумент. Таким образом, вы можете выполнить проверку границ с помощью

lo <= x < limit

Это выражение заключает в скобки, таким образом:

(lo <= x) < limit

И поэтому, если lo больше, чем x, выражение в скобках не будет выполнено, и, таким образом, все произойдет сбой. (Обычное выражение терпит неудачу, если любая его часть терпит неудачу.) Но если lo самое большее x, то lo <= x следует и возвращает x. Далее, конечно, машина сравнивает x < limit, и, если это удается, все успешно.

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

R.I.P.

1 голос
/ 14 января 2010

У MATLAB есть несколько способов обработки второй формы, которую вы перечислили выше:

if any(x == [something somethingelse]) ...
%# OR
if ismember(x,[something somethingelse]) ...
1 голос
/ 14 января 2010

На языках с оператором «switch» вы можете сделать:

switch (x)
{
    case 1:
    case 2:
    {
      // do whatever
      break;
    }

    default:
    {
        // else case
        break;       
    }
}

Это немного многословно, но в C вы можете скрыть это в макросе или в C ++, возможно, в шаблоне.

0 голосов
/ 15 января 2010

Если

A in [x, y, z]

считается действительным решением, тогда функция

in(A, x, y, z)

следует также считать допустимым решением, особенно для языка, который допускает перегрузку операторов, чтобы cmp (A, x, y, z) можно было сопоставить с

A in x y z

Обсуждения до сих пор обсуждались на

if (A == x or y or z).

А как насчет дела

if (A == x and y and z).

Поэтому мы будем использовать varargs, особенность, найденную в c, c ++, c # и java5.

Давайте проиллюстрируем Java.

boolean or(String lhs, String... rhs){
  for(String z: rhs){
    if (lhs.equals(z) return true;
  }
  return false;
}

boolean and(String lhs, String... rhs){
  for(String z: rhs){
    if (!lhs.equals(z) return false;
  }
  return true;
}

Varargs позволяют вам определять одну функцию, которая принимает переменное число аргументов, чтобы вы могли использовать тот же метод для сравнения

or (A, x)
or (A, x, y)
or (A, x, y, z)

Однако вышеприведенное определено только для сравнения строк, поэтому нам нужно будет создать пару методов для каждого типа аргумента. Но тогда в Java 5 есть дженерики.

<T extends Comparable<T>>boolean or(T lhs, T... rhs){
  for(T z: rhs){
    if (lhs.compareTo(z)==0) return true;
  }
  return false;
}

<T extends Comparable<T>>boolean and(T lhs, T... rhs){
  for(T z: rhs){
    if (lhs.compareTo(z)!=0) return false;
  }
  return true;
}

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

and(stringA, stringx, stringy)
or(dateA, datex)

Жаль, Java не позволяет перегрузить операторы, чтобы мы могли сделать

stringA && stringx, stringy
dateA || datex, datey, datez

В c ++ я никогда не пытался перегрузить оператор с помощью varargs, чтобы даже узнать, возможно ли это.

Повторяемость: Однако, возвращаясь к этому часам позже,

Мы могли бы определить класс

public class <T extends Comparable<T>> Comparigator{
  public Comparigator(T lhs){
    this.lhs = lhs;
  }
  final private T lhs;

  static public <T extends Comparable<T>> Comparigator is(T lhs){
    return (T)new Comparigator(lhs);
  }

  public boolean inAny(T... rhs){
    for(T z: rhs){
      if (this.lhs.compareTo(z)==0) return true;
    }
    return false;
  }

  public boolean inAll(T... rhs){
    for(T z: rhs){
      if (this.lhs.compareTo(z)!=0) return false;
    }
    return true;
  }

  public boolean gtAny(T... rhs){
    for(T z: rhs){
      if (this.lhs.compareTo(z)>0) return true;
    }
    return false;
  }

  public boolean gtAll(T... rhs){
    for(T z: rhs){
      if (this.lhs.compareTo(z)<=0) return false;
    }
    return true;
  }
}

Теперь нам вообще не нужна перегрузка оператора, и мы можем сделать

import Comparigator;
.....

is(A).inAny(x,y,z); // or
is(A).inAll(w,x,y,z); // and

is(B).gtAny(k,l,m);
is(C).gtAll(j,k);

И мы могли бы расширить его, и мы могли бы делать inany, inall, gtany, gtall, ltany, ltall и т. Д., Расширяя функциональность сравнения.

0 голосов
/ 14 января 2010

Perl: $foo ~~ ['string',$number,qr/regex/]

...