Retrieving data from a hash with array values in Perl 6 - raku

I have an array of 3 elements:
my #a = <x y z>;
Then I make a hash with Array values and make #a's contents one of its values:
my Array %h;
%h<a> = #a;
Later I retrieve this value and assign it to another array:
my #A = %h<a>;
But what I get in #A is not an array of 3 elements, but an array of one element, which is itself an array of 3 elements:
say #A; # [[x y z]]
say #A[0].elems; # 3
So, %h<a> was pushed into #A.
Where is the error in my code?
UPD: This seems to fix the problem, but doesn't improve my understanding. :)
my #A = #(%h<a>);
say #A; [x y z]

The reason this happens, is that the array #a must be put into a container to allow to be stored as a value in a Hash. And something inside a container will remain in the container when being stored into array #A. So, what you need is to get rid of the container when you assign to #A. Your solution is one way of getting rid of the container, but that creates an intermediate List, which could become expensive for large arrays.
As I said, you need to get rid of the container. Fortunately, we have a syntax for that: postfix <>:
my #a = <a b c>;
my %h = a => #a;
my #b = %h<a><>; # <-- note the <> here
dd #b; # Array #b = ["a", "b", "c"]
This would be the most efficient way if you really want #b to be mutable. Alternately, if you want #b to be just an alias of the original #a, you could also bind:
my #a = <a b c>;
my %h = a => #a;
my #b := %h<a>; # <-- note the := here
dd #b; # Array #a = ["a", "b", "c"]
Note that the dd output now shows #a as the name, as it now really is the same as #a: any changes to #a will now also show in #b and vice-versa. Which would be ok if you're not changing them anyway. If that's true in your situation, then this would be the most efficient way of doing this, both CPU-wise as well as memory-wise.

Related

How to divide every element in array by a certain number?

I have an array:
my #e = <60.922 20.946 8.721 7.292 4.306 2.821 2.765 2.752 2.741 2.725>
I would like to divide every element in the array by the minimum, however
#e /= #e.min
produced a single element, which isn't correct.
I've read https://docs.raku.org/type/Array but I don't understand the basic elements of Raku for this.
How can I divide every item in the array by the same number?
You can use the raku hyper & compound metaoperators like this:
#a >>/=>> #a.min
>>X>> means "apply operator X over all list items (with more items on the left)"
/= means "assign result of divide operator / to replace each original left hand item"
Use / instead of /= if you want to return the list of results but leave #a unchanged functional programming style.
[Edited according to #lizmat & #Sebastian comments]
my #a = 2, 3, 5, 7, 10;
my $div = #a.min;
$_ /= $div for #a;
say #a; # [1 1.5 2.5 3.5 5]
When you iterate over an array, you get mutable elements.
put #e.map( * / #e.min );
OR
put #e.map: * / #e.min;
Sample Input:
my #e = <60.922 20.946 8.721 7.292 4.306 2.821 2.765 2.752 2.741 2.725>;
Sample Output:
22.356697 7.686606 3.200367 2.675963 1.580183 1.035229 1.014679 1.009908 1.005872 1
If you want to continue working with the resultant values, assign the output to a new variable. Or overwrite the original #e array using the .= "back-assignment" operator [ short for #e = #e.map( … ) ]. In the Raku REPL:
~$ raku
Welcome to 𝐑𝐚𝐤𝐮𝐝𝐨™ v2021.06.
Implementing the 𝐑𝐚𝐤𝐮™ programming language v6.d.
Built on MoarVM version 2021.06.
To exit type 'exit' or '^D'
> my #e = <60.922 20.946 8.721 7.292 4.306 2.821 2.765 2.752 2.741 2.725>;
[60.922 20.946 8.721 7.292 4.306 2.821 2.765 2.752 2.741 2.725]
> #e .= map( * / #e.min );
[22.356697 7.686606 3.200367 2.675963 1.580183 1.035229 1.014679 1.009908 1.005872 1]
> put #e;
22.356697 7.686606 3.200367 2.675963 1.580183 1.035229 1.014679 1.009908 1.005872 1
>

Raku pop() order of execution

Isn't order of execution generally from left to right in Raku?
my #a = my #b = [9 , 3];
say (#a[1] - #a[0]) == (#b[1] R- #b[0]); # False {as expected}
say (#a.pop() - #a.pop()) == (#b.pop() R- #b.pop()); # True {Huh?!?}
This is what I get in Rakudo(tm) v2020.12 and 2021.07.
The first 2 lines make sense, but the third I can not fathom.
It is.
But you should realize that the minus infix operator is just a subroutine under the hood, taking 2 parameters that are evaluated left to right. So when you're saying:
$a - $b
you are in fact calling the infix:<-> sub:
infix:<->($a,$b);
The R meta-operator basically creates a wrap around the infix:<-> sub that reverses the arguments:
my &infix:<R->($a,$b) = &infix:<->.wrap: -> $a, $b { nextwith $b, $a }
So, if you do a:
$a R- $b
you are in fact doing a:
infix:<R->($a,$b)
which is then basically a:
infix:<->($b,$a)
Note that in the call to infix:<R-> in your example, $a become 3, and $b becomes 9 because the order of the arguments is processed left to right. This then calls infix:<->(3,9), producing the -6 value that you would also get without the R.
It may be a little counter-intuitive, but I consider this behaviour as correct. Although the documentation could probably use some additional explanation on this behaviour.
Let me emulate what I assumed was happening in line 3 of my code prefaced with #a is the same as #b is 9, 3 (big number then little number)
(#a.pop() - #a.pop()) == (#b.pop() R- #b.pop())
(3 - 9) == (3 R- 9)
( -6 ) == ( 6 )
False
...That was my expectation. But what raku seems to be doing is
(#a.pop() - #a.pop()) == (#b.pop() R- #b.pop())
#R meta-op swaps 1st `#b.pop()` with 2nd `#b.pop()`
(#a.pop() - #a.pop()) == (#b.pop() - #b.pop())
(3 - 9) == (3 - 9)
( -6 ) == ( -6 )
True
The R in R- swaps functions first, then calls the for values. Since they are the same function, the R in R- has no practical effect.
Side Note: In fuctional programming a 'pure' function will return the same value every time you call it with the same parameters. But pop is not 'pure'. Every call can produce different results. It needs to be used with care.
The R meta op not only reverses the operator, it will also reverse the order in which the operands will be evaluated.
sub term:<a> { say 'a'; '3' }
sub term:<b> { say 'b'; '9' }
say a ~ b;
a
b
ab
Note that a happened first.
If we use R, then b happens first instead.
say a R~ b;
b
a
ba
The problem is that in your code all of the pop calls are getting their data from the same source.
my #data = < a b a b >;
sub term:<l> { my $v = #data.shift; say "l=$v"; return $v }
sub term:<r> { my $v = #data.shift; say "r=$v"; return $v }
say l ~ r;
l=a
r=b
ab
say l R~ r;
r=a
l=b
ab
A way to get around that is to use the reduce meta operator with a list
[-](#a.pop, #a.pop) == [R-](#a.pop, #a.pop)
Or in some other way make sure the pop operations happen in the order you expect.
You could also just use the values directly from the array without using pop.
[-]( #a[0,1] ) == [R-]( #a[2,3] )
Let me emulate what happens by writing the logic one way for #a then manually reversing the operands for #b instead of using R:
my #a = my #b = [9 , 3];
sub apop { #a.pop }
sub bpop { #b.pop }
say apop - apop; # -6
say bpop - bpop; # -6 (operands *manually* reversed)
This not only appeals to my sense of intuition about what's going on, I'm thus far confused why you were confused and why Liz has said "It may be a little counter-intuitive" and you've said it is plain unintuitive!

Avoid creating temporary scalars when returning multiple arrays

Is it possible to avoid creating temporary scalars when returning multiple arrays from a function:
use v6;
sub func() {
my #a = 1..3;
my #b = 5..10;
return #a, #b;
}
my ($x, $y) = func();
my #x := $x;
my #y := $y;
say "x: ", #x; # OUTPUT: x: [1 2 3]
say "y: ", #y; # OUTPUT: y: [5 6 7 8 9 10]
I would like to avoid creating the temporary variables $x and $y.
Note: It is not possible to replace the function call with
my (#x, #y) = func()
since assignment of a list to an Array is eager and therefore both the returned arrays end up in #x.
Not either of:
my ($x, $y) = func();
my (#x, #y) = func();
But instead either of:
my (#x, #y) := func();
my ($x, $y) := func();
Use # to signal to P6 that, when it needs to distinguish whether something is singular -- "a single array" -- or plural -- "items contained in a single array" -- it should be treated as plural.
Use $ to signal the other way around -- it should be treated as singular.
You can always later explicitly reverse this by doing $#x -- to signal P6 should use the singular perspective for something you originally declared as plural -- or #$x to signal reversing the other way around.
For an analogy, think of a cake cut into several pieces. Is it a single thing or a bunch of pieces? Note also that # caches indexing of the pieces whereas $ just remembers that it's a cake. For large lists of things this can make a big difference.

How can I define an array filled with a single value in AMPL

How can I define an unary or multidimensional array filled with one value in AMPL?
Is there something like this?
param ARRAY {i in 1..1000} [i] := 20;
Should result in:
[20, 20, 20, ..., 20]
You were almost there, but I'll throw in a couple of extra options:
param ARRAY{i in 1..1000} := 20;
# sets all values to 20
param ARRAY{i in 1..1000} default 20;
# sets all values to 20 unless otherwise specified
param ARRAY{i in 1..1000};
for{i in 1..1000} {let ARRAY[i] = 20};
# iterates over the specified set.
# more useful if you want to do something like i^2 instead of a constant.
If you use the default 20 method, then display ARRAY; will only show the values that have been changed from default - it will look as if ARRAY is empty, but referencing specific elements will work OK.

How to make a union of two SetHashes in Perl 6?

Given two SetHashes, one or both of them can be empty. I want to add all the elements of the second SetHash to the first one.
Since the output of the union operator is a Set, the only (and supposedly not the best one) way I managed to do it is the following.
my SetHash $s1 = <a b c>.SetHash;
my SetHash $s2 = <c d e>.SetHash;
$s1 = ($s1 (|) $s2).SetHash; # SetHash(a b c d e)
UPD: Probably this is more simple, but having to convert to .keys makes me uncomfortable.
$s1{ $s2.keys } X= True; # SetHash(a b c d e)
I'm hoping Elizabeth Mattijsen will read over your question and our answers and either comment or provide her own answer. In the meantime here's my best shot:
my %s1 is SetHash = <a b c> ;
my %s2 is SetHash = <c d e> ;
%s1 = |%s1, |%s2 ; # SetHash(a b c d e)
Elizabeth implemented the is Set (and cousins ) capability for variables declared with the % sigil (i.e. variables that declare their primary nature to be Associative) in the Rakudo 2017.11 compiler release.
Prefix |, used within an expression that's an argument list, "flattens" its single argument if said single argument is composite (the relevant doc claims it must be a Capture, Pair, List, Map, or Hash):
say [ [1,2], [3,4]]; # [[1 2] [3 4]]
say [|[1,2], [3,4]]; # [1 2 [3 4]]
say [|1, 2, [3,4]]; # [1 2 [3 4]]