How to make an array of hashes in Perl 6? - raku

How to make a hash that has been pushed into an array independent of the "source" hash?
my %country;
my Hash #array;
%country{ 'country' } = 'France';
#array.push(%country);
%country{ 'country' } = 'Germany';
#array.push(%country);
.say for #array;
The output is:
{country => Germany}
{country => Germany}
And of course it's not what I want.

When you push the hash %country on to the array you are pushing the reference to %country. In this way, each array element will reference the same original hash %country. And when you change a value of the hash all array elements will reflect this change (since they all reference the same hash). If you want to create a new hash each time you push it, you can try push an anonymous hash instead. For example:
%country{ 'country' } = 'France';
#array.push({%country});
%country{ 'country' } = 'Germany';
#array.push({%country});
In this way, a reference to a copy of %country is pushed each time (instead of a reference to %country).
Output:
{country => France}
{country => Germany}

Just about every programming language has this issue. You're pushing the same hash onto the array more than once. When you change the hash, you change both references that are inside the array.
If you push different hashes onto the array, you'll see the result you expect:
my %a = ( country => 'China' );
my %b = ( country => 'USA' );
my Hash #array;
#array.push(%a);
#array.push(%b);
say #array.perl;
You can even copy the hash when you push it onto the array, instead of declaring two hashes. That will also solve this problem:
my %country;
my #array;
%country<country> = 'México';
#array.push(%country.list.hash);
%country<country> = 'Canada';
#array.push(%country.list.hash);
say #array.perl;
By the way, there are a lot of ways to copy a hash. The key is to get the key/values, then turn it back into a hash. Which hash constructor, and which flattening method you use are up to you. (.kv, .list, .pairs, .flat are all Hash methods that will get the elements sequentially, in one way or another. The way Håkon showed is more implicit, getting elements then creating another hash by syntax alone.)

If you just want a simple key value pair (not a multi part hash) consider Pairs?
my Pair #array;
#array.push( (:country<Germany>) );
#array.push( (country => "France") );
say #array;
say .kv for #array

Related

Matching the DataLoader API using SQL only

One of the examples for using DataLoader with Knex shows something this:
user: new DataLoader(ids => db.table('users')
.whereIn('id', ids).select()
.then(rows => ids.map(id => rows.find(x => x.id === id)))),
The map there is so that the keys in the array of keys always match up with the objects in the array of results, e.g. if object with id 2 is missing:
array of keys: [1,2,3]
array of results: [object1, undefined, object3]
If you left the map out, you'd get an unbalanced input/output (e.g. when querying for missing ids):
array of keys: [1,2,3]
array of results [object1, object3]
Is there any way to do the map bit with pure SQL?
It means that database doesn't have row with id 2 so whereIn doesn't return more that 2 rows. There is no way to do that in pure SQL with whereIn. With multiple subqueries it can be done, but it would be bad solution.

Deleting a complete folder in Redis

How can I delete a complete folder in redis, using DEL command OR in C# in StackExchange.Redis.
SomeFolder1:SomeSubfolder1:somekey1
SomeFolder1:SomeSubfolder1:somekey2
SomeFolder1:SomeSubfolder2:somekey1
How can I Del SomeFolder1:SomeSubfolder1 so remaining keys are
SomeFolder1:SomeSubfolder2:somekey1
There's no such thing as a "folder" in redis, and no functionality to del based on a pattern. Options:
use a database; you can have an arbitrary number of databases (each is numbered, the default is 0), and you can discard a database in a single operation: flushdb - so keep all this associated data in one database and you're sorted
use scan to iterate the matching keys, issuing a del for each match
note that scan is a server command, so you need:
const int db = 0;
var server = muxer.GetServer(...);
var db = muxer.GetDatabase(db);
foreach(var key in server.Keys(db, "SomeFolder1:SomeSubfolder1:*",
pageSize: 500))
{
db.KeyDelete(key, flags: CommandFlags.FireAndForget);
}
the FireAndForget allows you to ignore the individual replies, which means you aren't bound by latency and you don't have TPL overheads.
Fundamentally, though: redis is not meant to be used like this - if you find yourself scanning keys, you are doing something wrong. A more typical implementation might be to use a hash to store the folder (which each key/value pair inside the hash being the contents) - then deleting the hash is one operation. Alternatively, use a set to store the keys of the items inside each logical folder.
Hash approach:
hash = SomeFolder1:SomeSubfolder1
key = somekey1, value = ...
key = somekey2, value = ...
hash = SomeFolder1:SomeSubfolder2
key = somekey1, value = ...
Set approach:
set: SomeFolder1:SomeSubfolder1
somekey1
somekey2
set: SomeFolder1:SomeSubfolder2
somekey1
string: SomeFolder1:SomeSubfolder1:somekey1
value
string: SomeFolder1:SomeSubfolder1:somekey2
value
string: SomeFolder1:SomeSubfolder2:somekey1
value

"putting" a certain object to the screen from inside an array

I have an array, "templates".
puts templates
gives me the following output:
{"id"=>4, "subject"=>"invoice", "body"=>"dear sirs", "description"=>"banking", "groups"=>"123", 0=>4, 1=>"invoice", 2=>"dear sirs", 3=>"banking", 4=>"123"}
I would like to "put" a certain element e.g. "dear sirs". I have tried:
puts templates[2]
but this just returns nil. What is the correct way to do this?
You access "dear sirs" using the key that's associated with it, "body":
puts templates["body"]
Suppose if you have hash like this
#a = {"id"=>4, "subject"=>"invoice", "body"=>"dear sirs", "description"=>"banking", "groups"=>"123", 0=>4, 1=>"invoice", 2=>"dear sirs", 3=>"banking", 4=>"123"}
And if you want to get value of key name 'body', then you can get output like this,
puts #a['body'] //Output = dear sirs
puts #a['subject'] //Output = invoice
For more information for ruby hash Ruby Hash
If you want to get a hash value by numeric index then you can do templates.values[index]
e.g
templates.values[0] => 4
templates.values[1] => "invoice"
templates.values[2] => "dear sirs"
Note: My answer is based on strong assumptions that may not be true. I have provided steps to validate that.
In-case you are on older ruby version you need to do puts templates.inspect in-order to print a Hash. Therefore suggesting your variable templates is a String. Best way to verify:
templates.class
#=> returns Hash or String accordingly.
If it return String, you can proceed as follows:
Convert the String into Hash
hash = eval(templates)
#=> {"subject"=>"invoice", 0=>4, "description"=>"banking", 1=>"invoice", 2=>"dear sirs", "id"=>4, 3=>"banking", "body"=>"dear sirs", 4=>"123", "groups"=>"123"}
Now that its a Hash you can access any value using its key like:
hash[key]
#=> val
Example for your case:
hash[2]
#=> "dear sirs"

Rails getting single values from request

in Rails the create method in a Controller by default receives an HTTP request with different values.
By default new records are created like this:
#apo = Apo.new(params[:apo])
But how can i access single Values from this params hash?
I would like to create something like this:
#apo = Apo.new do |a|
a.name = $someVariable
a.value = $anotherVariable
a.quantity = -> here i want to have one value which is in params[:apo]
end
Do you understand what i´m looking for?
Tried million possibilities but it just doesn´t work.
Alternatively, is it possible, to create a second params hash in the view, which only saves this one value?
P.S. i don´t want to use JavaScript for doing this...
Thanks a lot!
params is special, and is set by Rails for each HTTP request. It's a hash in the form
{ :object => { :attrib1 => "value1", :attrib2 => "value2" ... }}
So you can reference the entire object with
params[:foo]
and individual attributes (fields) like
params[:foo][:bar]
A ActiveRecord model can be created in one call by passing a hash of values, as in your first example. But there are many other ways to create an instance. You can
def make_apo(some_value, another_value)
apo = Apo.new
apo.name = some_value
apo.value = another_value
end
Such a method will return an instance of Apo. In your case, if you have some values in params, change the above to accept params as another argument, or pass specific values when you call.
def make_apo(some_value, another_value, quantity, passed_params)
apo = Apo.new
apo.name = some_value
apo.value = another_value
apo.quantity = passed_params[:apo][:quantity]
end
But this is all a pretty unusual way of going about things. So don't just do this -- it's more by way of explaining what's going on than suggesting that you do this.

How to retrieve all hash values from a list in Redis?

In Redis, to store an array of objects we should use hash for the object and add its key to a list:
HMSET concept:unique_id name "concept"
...
LPUSH concepts concept:unique_id
...
I want to retrieve all hash values (or objects) in the list, but the list contains only hash keys so a two step command is necessary, right? This is how I'm doing in python:
def get_concepts():
list = r.lrange("concepts", 0, -1)
pipe = r.pipeline()
for key in list:
pipe.hgetall(key)
pipe.execute()
Is it necessary to iterate and fetch each individual item? Can it be more optimized?
You can use the SORT command to do this:
SORT concepts BY nosort GET concept:*->name GET concept:*->some_key
Where * will expand to each item in the list.
Add LIMIT offset count for pagination.
Note that you have to enumerate each field in the hash (each field you want to fetch).
Another option is to use the new (in redis 2.6) EVAL command to execute a Lua script in the redis server, which could do what you are suggesting, but server side.