Camelia

Is a value IN a given list of values?

How to find out if a given value is among some values? Similar to the IN operator in SQL or what you might expect from sets.

Note! This site is about Perl 6, the future version of Perl.
If you are looking for a solution for the current production version of Perl 5, please check out the Perl 5 tutorial.

Is a value IN a given list of values?

In Perl 6 there is the any() function that provides some functionality similar to the IN word in SQL. Let's see how it works:

Is this a weekday?

use v6;

my @weekdays = <Monday Tuesday Wednesday
    Thursday Friday Saturday Sunday>;

my $day = "Tuesday";
say $day eq any(@weekdays)
    ?? "$day is a weekday"
    !! "$day is NOT a weekday";

The above code will print

Tuesday is a weekday

What happens here is that perl will try to compare each element in the @weekdays array with the content of the $day scalar using eq. If any of them results in true then the expression is true.

Ternary operator in Perl 6

Side note: The ?? !! pair is the ternary operator of Perl 6. Its syntax is

CONDITION   ??    VALUE_IF_TRUE    !!    VALUE_IF_FALSE;

In other languages (including Perl 5) it is usually written as ? : but apparently it is not used that often so in order to please David A. Huffman and to give way for other, more frequently used operations, this operator became longer in Perl 6.

Is it still a weekday ?

For the completeness let's see what happens when none of the values match:

use v6;

my @weekdays = <Monday Tuesday Wednesday
    Thursday Friday Saturday Sunday>;

my $other = "Holiday";
say $other eq any(@weekdays)
    ?? "$other is a weekday"
    !! "$other is NOT a weekday";

The same code but without a matching value will print:

Holiday is NOT a weekday

Compare numbers with less than

In the next example we'll see that the any function can be used with other comparison operators such as the numerical less than operator:

use v6;

my @numbers = (6, -12, 20);
say any(@numbers) < 0
    ?? "There is a negative number"
    !! "No negative number here";

The result is:

There is a negative number

You can use other operators as well.

It works in case there is no negative number too:

use v6;

my @positive_numbers = (6, 12, 20);
say any(@positive_numbers) < 0
    ?? "There is a negative number"
    !! "No negative number here";

Output:

No negative number here

Other keywords: none, all, one

There are other functions too, not only the *any* function: (all, one and none)

use v6;

my @positive_numbers = (6, 12, 20);
say none(@positive_numbers) < 0
    ?? "No negative number here"
    !! "There is a negative number";

Will print:

No negative number here

use v6;

my @positive_numbers = (6, 12, 20);
say all(@positive_numbers) > 0
    ?? "All are positive numbers"
    !! "There is a NOT positive number";

Will print:

All are positive numbers

Use whichever fits the best the sentence you are writing.

Writing it shorter

Sometimes you have a value and need to check if it equals to any of the listed values:

use v6;

my $n = 12;
say ($n == 23 or $n == 42) ?? "ok" !! "not ok";  # not ok

With the any function you can also write like this:

use v6;

my $n = 12;
say $n == any(23, 42) ?? "ok" !! "not ok";  # not ok

The any function also has an infix operator version which is the single pipe, so you can also write this:

use v6;

my $n = 12;
say $n == 23|42 ?? "ok" !! "not ok";  # not ok

Junctions

What all these keywords and the relevant operators do is actually creating a data type that is called a Junction. It is a scalar value that holds multiple values in an unordered way. Similar to a set.

The first example could be written like this:

use v6;
my $weekdays = any <Monday Tuesday Wednesday Thursday Friday Saturday Sunday>;
my $day = "Tuesday";

say $day eq $weekdays
    ?? "$day is a weekday"
    !! "$day is NOT a weekday";

Here we created a junction instead of an array, and then used this junction in the comparison.

Other operations on Junctions

In addition to the comparison operations we saw earlier, we can do other operations on junctions. The operation will be executed on each one of the values in the junction and the result will be a new junction with the changed values:

use v6;

my $numbers = any(23, 42);
$numbers.perl.say;

$numbers++;
$numbers.perl.say;

This will print the perl representation of the junction:

any(23, 42)
any(24, 43)

Functions on Junctions

You can even pass junctions as parameters to functions. The function will be executed on each value separately in an undefined order, and the result will be another junction. For example if we would like to create the 3 character version of the months we can use the following code:

use v6;
my $months = any <January February March April May June
    July August September October November December>;

my $short_names = substr($months, 0, 3);
$short_names.perl.say;

Which should print

any("Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug",
  "Sep", "Oct", "Nov", "Dec");

Other Resource

The weekday example is based on the blog entry of Moritz Lenz I recommend looking at his Perl 6 and Perl 5 to Perl 6 blogs.

That's it for now.


The Perl 6 Tricks and Treats newsletter has been around for a while. If you are interested to get special notification when there is new content on this site, it is the best way to keep track:
Email:
Full name:
This is a newsletter temporarily running on my personal site (szabgab.com) using Mailman, till I implement an alternative system in Perl 6.
Gabor Szabo
Written by Gabor Szabo

Published on 2012-07-31



Comments

In the comments, please wrap your code snippets within <pre> </pre> tags and use spaces for indentation.
comments powered by Disqus

Perl 6 Tricks and Treats newsletter

Register to the free newsletter now, and get updates and news.
Email:
Name: