开发者

"or" operator without repeating the left hand condition again

开发者 https://www.devze.com 2022-12-16 15:56 出处:网络
Ever since I started programming properly using good old VB6 and up until present day, I often still get burned (and just have) by this in programming:

Ever since I started programming properly using good old VB6 and up until present day, I often still get burned (and just have) by this in programming:

if x == something or x == somethingelse

I often end up writing:

if x == something or somethingelse

Just out of pure interest, does any langauge/langu开发者_如何学运维ages out there support this?


Python does, kind of:

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

in simply checks whether an element occurs in a given list. Similarly, in Haskell:

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

I suppose that this can be done in most languages that allow for expressions of list type.


SQL has an in operator: x in (something, somethingelse), and there are many languages where you can implement something similar.

In c#, for instance, I use a custom extension method: if (x.In("something", "somethingelse"))...

edit here's the source of my c# extension method:

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;
}


In many programming languages you can do something like this:

myArray[something, somethingElse].Contains(x)

... but my guess is it would perform slightly worse.


The Icon programming language supports this idiom beautifully. Icon was designed by Ralph Griswold, who had already designed SNOBOL, and it's whole evaluation model is built on success or failure. Everything composes, and in principle every expression can produce multiple results. You can write such things as

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

Here's the evaluation model:

  1. First you evaluate the expression in parentheses and get something
  2. Then you compare something to x
  3. If they're not equal, the expression fails, and the evaluation engine automatically backtracks.
  4. During backtracking, evaluation of the parenthesized expression is resumed, and it succeeds again! This time it produces somethingelse.
  5. Let's suppose this comparison succeeds. Then the body of the if is evaluated and the program writes to standard output.

Here's another interesting scenario: every comparison either succeeds or fails, and if it succeeds, it returns its right-hand argument. So you can do bounds checking with

lo <= x < limit

This expression parenthesizes thusly:

(lo <= x) < limit

And so if lo is bigger than x, the parenthesized expression fails, and so the whole thing fails. (An ordinary expression fails if any part of it fails.) But if lo is at most x, then lo <= x succeeds and returns x. Next of course, the machine compares x < limit, and if that succeeds, the whole thing succeeds.

Icon was a beautifully consistent language, wonderfully easy to use, and underappreciated. But it was never well integrated with the operating system, and by the time they had a version that played well with Unix, Icon had already lost its chance at getting mindshare. But all language designers could learn a lot by studying it.

R.I.P.


In languages with a "switch" operator, you can do:

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

    default:
    {
        // else case
        break;       
    }
}

It's a bit verbose, but in C you could hide it in a macro or in C++ perhaps a template.


MATLAB has a couple ways to handle the second form you list above:

if any(x == [something somethingelse]) ...
%# OR
if ismember(x,[something somethingelse]) ...


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


If

A in [x, y, z]

is considered a valid solution then the function

in(A, x, y, z)

should be considered a valid solution too, especially for a language that allow operator overloading so that cmp(A, x, y, z) could be mapped to

A in x y z

Discussions so far have dwelt on

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

What about the case of

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

Therefore, we would use varargs, a feature found in c, c++, c# and java5.

Let's use java to illustrate.

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 allow you to define a single function that takes in a variable number of arguments so that you could use the same method to compare

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

However, the above is defined only for String comparisons, so that we would have to create a pair of methods for each arg type. But then in Java 5 there is generics.

<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;
}

So now you can do comparisons for any type that implements comparable interface.

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

Too bad, Java does not allow operator overloading so that we could do

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

In c++, I have never attempted operator overloading with varargs to even know if it is possible.

Revisit: However, revisiting this hours later,

We could define a class

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;
  }
}

Now, we don't need operator overloading at all and we can do

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);

And we could expand it and we could do inany, inall, gtany, gtall, ltany, ltall, etc by expanding the comparison functionality.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号