Recursively building nested hash from a simple array - raku

Got this:
my #list = <one two three>;
my %hash;
my $item1 = #list.shift;
%hash{$item1} = {$item1 => 1};
my $item2 = #list.shift;
%hash{$item1} = {$item2 => 1};
my $item3 = #list.shift;
%hash{$item1}{$item2} = {$item3 => 1};
say %hash;
Outputs this desired data structure:
{one => {two => {three => 1}}}
Obviously, this would be better if it were recursive, so I wrote this:
sub get-hash(%parent-hash, $last-item, *#list) {
my $item = #list.shift;
%parent-hash{$last-item} = { $item => 1 };
get-hash(%parent-hash{$last-item}, $item, #list) if #list;
return %parent-hash<root>;
}
%hash = get-hash({}, 'root', #list2);
Output:
{one => {two => {three => 1}}}
Though it works, it feels inelegant, especially having to pass in a root argument to the sub and then removing it. Any suggestions?

In the upcoming Raku version, there's a neat way to do this:
use v6.e.PREVIEW;
my #list = <one two three>;
my %hash;
%hash{||#list} = 1;
say %hash;
The || indicates that you want to use the list as multi-dimensional hash keys.
If you want to stick to things in the current released language versions, you can still call the operator directly, since it's only the syntax sugar that is missing:
my #list = <one two three>;
my %hash;
postcircumfix:<{; }>(%hash, #list) = 1;
say %hash
The output in either case is as you wish:
{one => {two => {three => 1}}}

OK, playing around with the order of the arguments helped simplify things a bit:
sub get-hash(#list, %parent-hash = {}, $last-item = 'root') {
my $item = #list.shift;
%parent-hash{$last-item} = { $item => 1 };
get-hash(#list, %parent-hash{$last-item}, $item) if #list;
return %parent-hash<root>;
}
my #list2 = <one two three>;
%hash = get-hash(#list2);

If you want ’key-value’ structure Pair
my #list = <one two three>;
say [=>] |#list, 1
If you really need Hash
<one two three>
andthen |$_, 1
andthen .reduce: sub ($x,$y) is assoc<right> { %( $x => $y ) }\
andthen .say
or
<one two three>
andthen 1, |.reverse
andthen .reduce: { %( $^y => $^x ) }\
andthen .say

Related

What is the difference between using Raku's Code.assuming method and using an anonymous Block or Sub?

The Raku docs say that Code.assuming
Returns a Callable that implements the same behavior as the original, but has the values passed to .assuming already bound to the corresponding parameters.
What is the difference between using .assuming and wrapping the Code in an anonymous Block (or Sub) that calls the inner function with some parameters already bound?
For instance, in the code below, what is the difference between &surname-public (an example the docs provide for .assuming) and &surname-block;
sub longer-names ( $first, $middle, $last, $suffix ) {
say "Name is $first $middle $last $suffix";
}
my &surname-public = &longer-names.assuming( *, *, 'Public', * );
my &surname-block = -> $a,$b,$c { longer-names($a, $b, 'Public', $c) }
surname-public( 'Joe', 'Q.', 'Jr.'); # OUTPUT: «Name is Joe Q. Public Jr.»
surname-block( 'Joe', 'Q.', 'Jr.'); # OUTPUT: «Name is Joe Q. Public Jr.»
I see that .assuming saves a bit of length and could, in some contexts, be a bit clearer. But I strongly suspect that I'm missing some other difference.
There really isn't a difference.
While the code to implement .assuming() is almost 300 lines, the important bit is only about ten lines of code.
$f = EVAL sprintf(
'{ my $res = (my proto __PRIMED_ANON (%s) { {*} });
my multi __PRIMED_ANON (|%s(%s)) {
my %%chash := %s.hash;
$self(%s%s |{ %%ahash, %%chash });
};
$res }()',
$primed_sig, $capwrap, $primed_sig, $capwrap,
(flat #clist).join(", "),
(#clist ?? ',' !! '')
);
The rest of the code in .assuming is mostly about pulling information out of the signatures.
Let's take your code and insert it into that sprintf.
(Not exactly the same, but close enough for our purposes.)
{
my $res = (
# $primed_sig v----------------------v
my proto __PRIMED_ANON ($first, $middle, $suffix) { {*} }
);
# $capwrap vv
# $primed_sig v----------------------v
my multi __PRIMED_ANON (|__ ($first, $middle, $suffix)) {
# $capwrap vv
my %chash := __.hash;
# v---------------------------v #clist
$self(__[0], __[1], 'Public', __[2], |{ %ahash, %chash });
};
# return the proto
$res
}()
If we simplify it, and tailor it to your code
my &surname-public = {
my $res = (
my proto __PRIMED_ANON ($first, $middle, $suffix) { {*} }
);
my multi __PRIMED_ANON ( $first, $middle, $suffix ) {
longer-names( $first, $middle, 'Public', $suffix )
};
$res
}()
We can simplify it further by just using a pointy block.
my &surname-public = -> $first, $middle, $suffix {
longer-names( $first, $middle, 'Public', $suffix )
};
Also by just using single letter parameter names.
my &surname-public = -> $a,$b,$c { longer-names($a, $b, 'Public', $c) }
Like I said, there really isn't a difference.
In the future, it may be more beneficial to use .assuming(). After it gets rewritten to use RakuAST.

Implement Phalcon 4 Database Existence validator (similar to Uniqueness)

Often I need to validate if given value is existing in certain column (attribute) of a table (model).
This can be useful in foreign keys of a model, to check if the given values exists.
Most probably the validation logic can be mostly the same as for Uniqueness, except the comparison here can be something like > 0.
A possible usage scenario could be like below:
$validator->add(
'organization_id',
new ExistenceOnDbValidator(
[
'model' => Organization::class,
'expr'=> ' id = %s ',
'excludeNullValue'=> true,
'message' => 'Organization does not exist.',
]
)
);
Finally I implemented myself a validator called ExistenceOnDbValidator and it works fine.
Usage
$validator = new Validation();
$validator->add(
'organization_id',
new ExistenceOnDbValidator(
[
'model' => Organization::class,
'expr' => ' id = %s ',
'ignoreNullValue' => false,
'message' => 'Selected organization does not exist.',
]
)
);
Implenentation
use Phalcon\Messages\Message;
use Phalcon\Validation;
use Phalcon\Validation\AbstractValidator;
use Phalcon\Validation\ValidatorInterface;
class ExistenceOnDb extends AbstractValidator implements ValidatorInterface
{
public function validate(Validation $validator, $attribute): bool
{
$expr = $this->getOption('expr');
$model = $this->getOption('model');
$value = $validator->getValue($attribute);
$ignoreNullValue = true;
if ($this->hasOption('ignoreNullValue')) {
$ignoreNullValue = $this->getOption('ignoreNullValue');
}
if ((is_null($value) || empty($value)) && $ignoreNullValue == true) {
return true;
}
$expr = sprintf(
$expr,
$value,
);
$result = $model::findFirst($expr);
if ((is_null($result) || empty($result))) {
$message = $this->getOption('message');
$validator->appendMessage(new Message($message));
return false;
}
return true;
}
}

How do I declare a hash of hashes of numbers in Perl 6?

A hash, by default, converts all keys to strings. This causes issues when your keys are numbers which may be close:
> my %h; %h{1/3} = 1; %h{0.333333} = 2; dd %h;
Hash %h = {"0.333333" => 2}
This can, of course, be fixed as follows:
> my %h{Real}; %h{1/3} = 1; %h{0.333333} = 2; dd %h;
Hash[Any,Real] %h = (my Any %{Real} = 0.333333 => 2, <1/3> => 1)
But now I need a hash of hashes of numbers, e.g. { 1/3 => { 2/3 => 1, 0.666667 => 2 } }.
> my %h{Real}; %h{1/3}{2/3} = 1; %h{1/3}{0.666667} = 2; dd %h;
Hash[Any,Real] %h = (my Any %{Real} = <1/3> => ${"0.666667" => 2})
How do I fix that?
Best I can figure out is the following workaround:
> my %h{Real}; %h{1/3} //= my %{Real}; %h{1/3}{2/3} = 1; %h{1/3}{0.666667} = 2; dd %h;
Hash[Any,Real] %h = (my Any %{Real} = <1/3> => $(my Any %{Real} = <2/3> => 1, 0.666667 => 2))
but that's just annoying.
The following works:
my Hash[Real,Real] %h{Real};
%h{1/3} .= new;
%h{1/3}{2/3} = 1;
Which is not great.
The following also works as a work-around.
my Hash[Real,Real] %h{Real};
%h does role {
method AT-KEY (|) is raw {
my \result = callsame;
result .= new unless defined result;
result
}
}
%h{1/3}{2/3} = 1;
say %h{1/3}{2/3}; # 1
If you have more than one such variable:
role Auto-Instantiate {
method AT-KEY (|) is raw {
my \result = callsame;
result .= new unless defined result;
result
}
}
my Hash[Real,Real] %h{Real} does Auto-Instantiate;

Perl: DBIx::Class Beginner - Subsetting Relationships and Prefetching

Okay, I'm new to DBIx::Class. I have a one-to-many relationship set up, like so:
User -> has_many -> Addresses
Okay, good. I can do a query, and call it prefetching JOINed tables, like so:
Foo::DBIC->storage->debug(1); # output SQL to STDOUT
my $user = Foo::DBIC->resultset('Users')->search({}, {
prefetch => [ 'addresses' ],
join => [ 'addresses' ],
rows => 1
})->single;
for my $address ($user->addresses->all) {
say $address->zip_code;
}
Two tables, one SQL query (verified via debug). All is well.
Now, however, let's say I want to write an overload method or two in Foo::DBIC::Result::Users that returns a subset of addresses, based on certain criteria. Here's what I've added to the Users class:
sub home_addresses {
my $self = shift;
return $self->search_related('addresses', { address_type => 'home' });
}
sub business_addresses {
my $self = shift;
return $self->search_related('addresses', { address_type => 'business' });
}
I can call these overloads like so, and they work:
for my $address ($user->home_addresses->all) {
say $address->zip_code;
}
However, this ignores the fact that I've prefetched my join, and it performs ADDITIONAL QUERIES (as if I've not prefetched and joined anything).
So, my question is this: how do I define an overload method that returns a subset of a related table, but uses the already prefetched join? (just appending a WHERE clause to the prefetch)...
My problem is that if I have a lot of the overloaded methods returning related table subsets, my query count can blow up; especially if I'm calling them from within a loop.
I have reasons for doing this that are, of course, ugly. My real life schema is a lot, lot, lot messier than Users and Addresses, and I'm trying to abstract away ugly as best I can.
Thanks!
something like this for home_addresses might work:
sub home_addresses {
my $self = shift;
my $addresses = $self->addresses;
my $home_addresses;
while (my $row = $addresses->next()) {
push #$home_addresses, $row if $row->address_type() eq 'home';
}
my $home_rs = $addresses->result_source->resultset;
$home_rs->set_cache( $home_addresses );
$home_rs;
}
Alternatively, if there a lot of address types something like this:
sub addresses_by_type {
my $self = shift;
my $addresses = $self->addresses;
my $type;
my $rs_type;
while (my $row = $addresses->next()) {
push #{$type->{"".$row->address_type}},
$row;
}
for (keys %$type) {
my $new_rs = $addresses->result_source->resultset;
$new_rs->set_cache( $type->{$_} );
$rs_type->{$_} = $new_rs
}
return $rs_type
}
which you could access the 'home' addresses from like this:
while (my $r = $user->next) {
use Data::Dumper;
local $Data::Dumper::Maxdepth = 2;
print $r->username,"\n";
my $d = $r->addresses_by_type();
my $a = $d->{home};
while (defined $a and my $ar = $a->next) {
print $ar->address,"\n";
}
}
Could you try something like this:
sub home_addresses {
my $self = shift;
my $return = [];
my #addresses = $self->addresses->all();
foreach my $row (#addresses) {
push #$return, $row if $row->address_type() eq 'home';
}
return $return;
}

codeigniter pagination for a query

So far found plenty of help to get the pagination working for a get(table) command.
What I need is to pick only few of the entries from a couple of linked tables based on a sql where statement.
I guess the query command is the one to use but in this case how do I do the pagination since that command does not take extra parameters such $config['per_page']
Thanks for the help
Without any more info to go on I think that what you're looking for is something like the following.
public function pagination_example($account_id)
{
$params = $this->uri->ruri_to_assoc(3, array('page'));
$where = array(
'account_id' => $account_id,
'active' => 1
);
$limit = array(
'limit' => 10,
'offset' => (!empty($params['page'])) ? $params['page'] : 0
);
$this->load->model('pagination_model');
$data['my_data'] = $this->pagination_model->get_my_data($where, $limit);
foreach($this->uri->segment_array() as $key => $segment)
{
if($segment == 'page')
{
$segment_id = $key + 1;
}
}
if(isset($segment_id))
{
$config['uri_segment'] = $segment_id;
}
else
{
$config['uri_segment'] = 0;
}
$config['base_url'] = 'http://'.$_SERVER['HTTP_HOST'].'/controller_name/method_name/whatever_your_other_parameters_are/page/';
$config['total_rows'] = $this->pagination_model->get_num_total_rows();// Make a method that will figure out the total number
$config['per_page'] = '10';
$this->load->library('pagination');
$this->pagination->initialize($config);
$data['pagination'] = $this->pagination->create_links();
$this->load->view('pagination_example_view', $data);
}
// pagination_model
public function get_my_data($where = array(), $limit = array())
{
$this->db
->select('whatever')
->from('wherever')
->where($where)
->limit($limit['limit'], $limit['offset']);
$query = $this->db->get();
if($query->num_rows() > 0)
{
$data = $query->result_array();
return $data;
}
return FALSE;
}
This should at least get you on the right track
If this isn't what you're asking I'd happy to help more if you can be a little more specific. How about some of your code.
The only other options that I can think of would be to either code a count in your select statement or not limit the query and use array_slice to select a portion of the returned array.