Check if all elements of list are prime in Raku - mapreduce

my #g = (1,2,3,4);
say reduce {is-prime}, #g; # ==> gives error
say reduce {is-prime *}, #g; #==> gives error
say reduce {is-prime}, (1,2,3,4); # ==> gives error
say so is-prime #g.all; # ==> gives error
How to check if all elements of list are prime in Raku?

The answers above are all helpful, but they fail to explain why your solution does not work. Basically reduce is not going to apply a function (in your case, is-prime) to every member of a list. You want map for that. The error says
Calling is-prime() will never work with signature of the proto ($, *%)
Because reduce expects an infix, thus binary, function, or a function with two arguments; what it does is to apply them to the first pair of elements, then to the result and the third element, and so on. Last statement does not work for a similar reason: you are calling is-prime with a list argument, not a single argument.

You're basically asking: are there any elements in this list which are not prime? I would write that as:
say "not all prime" if #g.first: !*.is-prime;
Please note though, that apparently 1 is not considered prime according to the is-prime function:
say 1.is-prime; # False
so the first would trigger on the 1 in your example, not on the 4.

There are of course may ways to do this. A very explicit way is using a for loop:
for #g -> $g {
if $g.is-prime {
say $g;
}
}
Or with a grep (you could leave the $_ implicit):
#g.grep({ $_.is-prime }).say
Both above are assuming you really want to filter the primes out. Of course you can also really check each number and get a boolean:
#g.map({ .is-prime }).say

There is a big problem with this:
say reduce {is-prime}, #g;
You created a lambda:
{ }
The only thing it does is calls a function:
is-prime
You didn't give the function any arguments though.
Is it just supposed to guess what the arguments should be?
If you meant to pass in is-prime as a reference, you should have used &is-prime rather than {is-prime}.
Of course that still wouldn't have worked.
The other problem is that reduce operates by recursively combining values.
It can't do that if it operates on one argument at a time.
The bare block lambda {}, takes zero or one argument, not two or more.
reduce is often combined with map.
It happens so often that there is a Wikipedia page about MapReduce.
say ( map &is-prime, #g ==> reduce { $^a and $^b } );
# False
say ( map &is-prime, 2,3,5 ==> reduce { $^a and $^b } );
# True
I wrote it that way so that map would be in the line before reduce, but perhaps it would be more clear this way:
say reduce {$^a and $^b}, map &is-prime, 2,3,5;
# True
reduce with an infix operator is so common that there is a shorter way to write it.
say [and] map &is-prime, 2,3,5;
# True
Of course it would be better to just find the first value that isn't prime, and say the inverse.
Since if there is even a single value that isn't prime that would mean they can't all be primes.
You have to be careful though, as you may think something like this would always work:
not #g.first: !*.is-prime;
It does happen to work for the values you gave it, but may not always.
first returns Nil if it can't find the value.
not (2,3,5).first: !*.is-prime;
# not Nil === True
not (2,3,4).first: !*.is-prime;
# not 4 === False
not (2,3,0,4).first: !*.is-prime;
# not 0 === True
That last one returned 0 which when combined with not returns True.
You could fix this with defined.
not defined (2,3,0,4).first: !*.is-prime;
# False
This only works if first wouldn't return an undefined element that happens to be in the list.
(Int,Any).first: Real
# Int
defined (Int,Any).first: Real
# False
You could fix that by asking for the index instead of the value.
You of course still need defined.
(Int,Any).first: :k, Real
# 0
defined (Int,Any).first: :k, Real
# True
The other way to fix it is to just use grep.
not (2,3,0,4).grep: !*.is-prime;
# not (0,4) === False
Since grep always returns a List, you don't have to worry about checking for 0 or undefined elements.
(A List is True if it contains any elements, no matter what the values.)
grep is smart enough to know that if you coerce to Bool that it can stop upon finding the first value.
So it short-circuits the same as if you had used first.
This results in some fairly funky code, with those two negating operators. So it should be put into a function.
sub all-prime ( +#_ ) {
# return False if we find any non-prime
not #_.grep: !*.is-prime
# grep short-circuits in Bool context, so this will stop early
}
This could still fail if you give it something weird
all-prime 2,3,5, Date.today;
# ERROR: No such method 'is-prime' for invocant of type 'Date'
If you care, add some error handling.
sub all-prime ( +#_ ) {
# return Nil if there was an error
CATCH { default { return Nil }}
# return False if we find any non-prime
not #_.grep: !*.is-prime
}
all-prime 2,3,5, Date.today;
# Nil

use the all junction:
say so all #g».is-prime; # False

Related

TACL How to use multiple Arguments

I was wondering if we have any TACL experts out there can can help me answer probably a very basic question.
How do you inject multiple arguments into you routine.
This is what I have currently so far
[#CASE [#ARGUMENT / VALUE job_id/number /minimum [min_job], maximum [max_job]/
otherwise]
|1|#output Job Number = [job_id]
|otherwise|
#output Bad number - Must be a number between [min_job] & [max_job]
#return
]
I have been told you need to use a second #ARGUMENT statement to get it to work but I have had no such luck getting it to work. And the PDF guides don't help to much.
Any ideas/answers would be great
Thanks.
The #CASE statement isn't required if your arguments are positional and of one type (i.e. you know what you are getting and in what order). In that case you can just use a sequence of #ARGUMENT statements to get the arguments.
In your example #ARGUMENT accepts either a number in a range or anything else - the OTHERWISE bit. The #CASE statement then tells you which of those two you got, 1 or 2.
#ARGUMENT can do data validation for you (you may recognize the output from some of the TACL routines that come with the operating system).
So you can write something like this:
SINK [#ARGUMENT / VALUE job_id/number /minimum [min_job], maximum [max_job]/]
The SINK just tosses away the expansion of the #ARGUMENT, you don't need it since you only accept a number and fail otherwise.
I figured out a way but idk if it is the best way to do it.
It seems that for one an Argument statement needs to always be in a #CASE statement so all I basically did was mirror the above and just altered it for text rather than use integer.
If you know of any other/better ways let me know :)
It find it best to use CASE when you have multiple types of argument
input to process. Kind of mocked up how I would see multiple argument
types being used in the context that you shared with the CASE
expression:
?TACL ROUTINE
#FRAME
#PUSH JOB_ID MIN_JOB MAX_JOB
#SETMANY MIN_JOB MAX_JOB , 1 3
[#DEF VALID_KEYWORDS TEXT |BODY| THISJOB THATJOB SOMEOTHERJOB]
[#CASE
[#ARGUMENT/VALUE JOB_ID/
NUMBER/MINIMUM [MIN_JOB],MAXIMUM [MAX_JOB]/
KEYWORD/WORDLIST [VALID_KEYWORDS]/
STRING
OTHERWISE
]
| 1 |
#OUTPUT VALID JOB NUMBER = [JOB_ID]
| 2 |
#OUTPUT VALID KEYWORD = [JOB_ID]
| 3 |
#OUTPUT VALID STRING = [JOB_ID]
| OTHERWISE |
#OUTPUT NOT A NUMBER, KEYWORD, OR A STRING
#OUTPUT MUST BE ONE OF:
#OUTPUT A NUMBER IN THE RANGE OF: [MIN_JOB] TO [MAX_JOB]
#OUTPUT A KEYWORD IN THIS LIST: [VALID_KEYWORDS]
#OUTPUT OR A STRING OF CHARACTERS
#RETURN
]
#OUTPUT
#OUTPUT NOW WE ARE USING ARGUMENT [JOB_ID] !!!
TIME
#UNFRAME

XQuery get Random Text from a List

Suppose I have a list of 100 String Element and I want to get 50 of these random Text string to be returned Randomly.
I try to do this:
let $list := ("a","b",..."element number 100")
return xdmp:random(100)
This query return one string, I want to return back 50 strings that are distinct from each other.
Easiest to order by xdmp:random() and limit to the first 50:
(for $x in (1 to 100)
order by xdmp:random()
return $x
)[1 to 50]
xdmp:random() (as well as xdmp:elapsed-time()) return different values at each call. It would be rather impractical if it wouldn't. This opposed to for instance fn:current-dateTime() which gives the same value throughout one execution run.
Ghislain is making a good first attempt, but as also pointed out by BenW, even though xdmp:random() does return different results each time, it is not said they are unique throughout one execution run. Collisions on its 64-bit max scale are rare (though still possible), but on small scale like 10's or 100's it is likely to have some accidental repetition. It is wise to eliminate the texts from the list once chosen.
BenW beat me to posting an alternative to Ghislain, and it looks similar, but uses less lines. Posting it anyhow, in the hope someone finds it useful:
declare function local:getRandomTexts($list, $count) {
if ($count > 0 and exists($list)) then
let $random := xdmp:random(count($list) - 1) + 1
let $text := $list[$random]
return ($text, local:getRandomTexts($list[. != $text], $count - 1))
else ()
};
let $list :=
for $i in (1 to 26)
return fn:codepoints-to-string(64 + $i)
for $t in local:getRandomTexts($list, 100)
order by $t
return $t
HTH!
If you are saying the 50 strings must be distinct from one another, as in, no repeats allowed, then even if xdmp:random() does return different values when called repeatedly in the same query, getting 50 random positions in the same list is not sufficient, because there may be repeats. You need to get random positions from 50 different lists.
declare function local:pickSomeFromList($some as xs:integer, $listIn as xs:string*, $listOut as xs:string*) as xs:string* {
if($some = 0 or not($listIn)) then $listOut
else
let $random := xdmp:random(count($listIn) - 1) + 1
return local:pickSomeFromList(
$some - 1,
($listIn[fn:position() lt $random],$listIn[fn:position() gt $random]),
($listOut, $listIn[$random])
)
};
let $list := ("a","b","c","d","e","f","g","h","i","element number 10")
return local:pickSomeFromList(5, $list, ())
Assuming it returns a different result at every call (but I cannot tell from the documentation of xdmp:random whether it is the case), the following code returns 50 strings from the list picked at random (but not necessarily distinct):
let $list := ("a","b",..."element number 100")
for $i in 1 to 50
let $position = 1 + xdmp:random(99)
return $list[$position]
However, the exact behavior of xdmp:random, that is, whether it returns identical results across calls, depends on how the MarkLogic engine supports or treats nondeterministic behavior, which is outside of the scope of the XQuery specification. Strict adherence to the specification would actually return 50 times the same result with the above query.
XQuery 3.1 provides a random number generator with which you can control the seed. This allows you to generate as many numbers as you want by chaining calls, while only using interoperable behavior and staying within a fully deterministic realm.
Edit: here is a query (still assuming calls to xdmp:random are made each time) that should make sure that 50 distinct strings from the list are taken following grtjn's remark. It uses a group by clause and relies on a lazy evaluation for taking the first 50.
let $list := ("a","b",..."element number 100")
let $positions := (
for $i in 1 to 100000 (: can be adjusted to make sure we get 50 distinct :)
group by $position = 1 + xdmp:random(count($list) - 1)
return $position
)[position() le 50]
return $list[position() = $positions]
I think hunterhacker's proposal for computing the $positions is even better though.

How to check through an entire list in Python for a condition fulfillment

So I'm trying to make a single line to check if a single element in Python list fits the criteria, but my current code will keep the loop going even if it hits a "True" -mark and thus only the last element counts for the check:
if [[CheckStatus(value, outsidevalue)] for value in valuelist] is True:
magic
(CheckStatus returns either True or False for every single value compared to outsidevalue and is supposed to accept is as true if a single value returns True)
that will always be false:
if [[CheckStatus(value, outsidevalue)] for value in valuelist] is True:
because you're comparing a list with a boolean.
What you want is any:
if any(CheckStatus(value, outsidevalue) for value in valuelist):
any iterates on the generator comprehension, calling your function on all elements until True is found (note that the inside square brackets have been removed, and we don't need to create a list comprehension, just a generator comprehension, which is faster)

python try-except, exception handling

I have 10 links in a list, upon clicked,which will open a new window. Different links would yield different set of pages, however i have 3 common elements for all 10 links.
Following is the function example.
def handle_window(self):
self.driver.go_to_new_window()
try: # block 1
elements = ["element1", "element2", "element3"]
for element in elements:
try: #block 2
self.assertEqual(True, is_exist_in_new_window(element)))
except:
continue
except:
# in 'try block 2' if assert yields true at least once,
print 'passed'
# if it fails for all 3 elements,
print 'failed'
self.driver.close_current_window()
self.driver.go_to_main_window()
I am not sure how do i evaluate the results of 'try block 2', so that to do some action in block 1.
Any possible solutions ?
If "element1", etc. are meant to be CSS selectors, the most efficient way would be:
elements = ["element1", "element2", "element3"]
self.assertTrue(exists_in_new_window(",".join(elements)))
(I've renamed is_exist_in_new_window to exists_in_new_window.) The , operator in CSS means "or". So the CSS selector passed to exists_in_new_window means you are looking for "element1" or "element2" or "element3". Doing it this way will need one round-trip between the Selenium client and the browser, no matter what. Note that the code above is not meant to handle meaningfully the case where elements is a zero-length list.
With XPath selectors you could use the | operator to perform a similar transformation. In this case, I would want to additionally use parentheses to preserve semantics of the individual selectors so something like "(" + ")|(".join(elements) + ")". (I believe the semantics issue does not arise in CSS due to CSS' very rigid syntax.)
In the more general case where it is not possible to combine the search criteria into one expression, one can fall back onto alecxe's suggestion:
elements = ["element1", "element2", "element3"]
self.assertTrue(any((exists_in_new_window(element) for element in elements)))
This method causes a minimum of min(1, len(elements)) round-trips between the Selenium client and the browser and a maximum of len(elements) depending on what is present on the page.
You can use any() to check if at least one element existed on a page:
elements = ["element1", "element2", "element3"]
value = any((is_exist_in_new_window(element) for element in elements))
self.assertTrue(value)
This code assumes is_exist_in_new_window() returns True or False.
Hope that helps.

Django OR query

How would I do:
FinancialStatements.objects.get(statement_id=statement_id)
or SalesStatements.objects.get(statement_id=statement_id)
The result will always yield one result.
I ended up using the try/except route here:
try:
statement_object = FinancialStatements.objects.get(statement_id=statement_id)
except FinancialStatements.DoesNotExist:
statement_object = SalesStatements.objects.get(statement_id=statement_id)
Why not simply do:
result = (FinancialStatements.objects.filter(statement_id=statement_id) or
SalesStatements.objects.filter(statement_id=statement_id))
This should work, because filter returns a list - and an empty list if no entries match. An empty list evaluates to false in python's boolean logic, e.g. try running:
print [] or "hello"
(Just as a check, compare print ["Hi"] or "hello")
So, if the first query returns empty, the second will then be run. However, if the first matches anything, this will be result and the second query will be ignored.
Addendum: result will then be of a list type - you'll need to extract the (one and only) element with result[0].