Duplicate keys of hash in ruby - arrays

I know that hash doesn't store duplicate keys. But I want to know if that default behaviour can be changed according to requirement, Is that possible?
I will give the sample code here
keys_array = [ 'key1', 'key2' ]
values_array = [
{"A": { "id": "1" }},
{"B": { "id": "2" }}
]
results = keys_array.zip(values_array ).to_h
Here output is exactly what I wanted
{"key1"=>{:A=>{:id=>"1"}}, "key2"=>{:B=>{:id=>"2"}}}
But If the keys get repeated , for example
keys_array = [ 'key1', 'key1' ] in which 'key1' key is repeated,
result will be {"key1"=>{:B=>{:id=>"2"}}}
But I want
{"key1"=>{:A=>{:id=>"1"}}, "key1"=>{:B=>{:id=>"2"}}}
I know about grouping and all , but it will change the result format
So I don't want to use that
I want this result {"key1"=>{:A=>{:id=>"1"}}, "key1"=>{:B=>{:id=>"2"}}} where key1 is a repeated key.
Also please note that these array values are not fixed , its dynamic
Greatly appreciate your help!

You can alter the behavior of a hash with compare_by_identity.
h = Hash.new.compare_by_identity
h["key1"] = 1
h["key1"] = 2
p h #=> {"key1"=>1, "key1"=>2}
I've never seen a useful way for this.

The data structure you are looking for is called a multimap. It is, of course, possible to implement one in Ruby. You just have to do it. (Or find a library that does it for you.)
However, neither the core nor the standard library contain a multimap implementation.

No way with a hash, you could use an array of hashes instead:
[{"key1"=>{:A=>{:id=>"1"}}}, {"key1"=>{:B=>{:id=>"2"}}}]

Related

ElasticSearch 5.1 Filtering by Comparing Arrays

I have a keyword array field (say f) and I want to filter documents with an exact array (e.g. filter docs with f = [1, 3, 6] exactly, same order and number of terms).
What is the best way of doing this?
Regards
One way to achieve this is to add a script to the query which would also check the number of elements in the array.
it script would be something like
"filters": [
{
"script": {
"script": "doc['f'].values.length == 3"
}
},
{
"terms": {
"f": [
1,
3,
6
],
"execution": "and"
}
}
]
Hope you get the idea.
I think an even better idea would be to store the array as a string (if there are not many changes to the structure of the graph) and matching the string directly. This would be much faster too.

How to build a new Ruby array from a Hash keys

I want to build a new array starting from a hash with the following format:
HashConst = {[120,240] => 60, [240,480]=> 30} #Constant
I need to build a new array and assign as value to a new constant with the following format:
[ [[120,240] ,1], [[240,480], 1] ]
I tried :
NewArrayConst = HashConst.keys.each{ |res| [res, 1]}
but I get instead
[ [120,240], [240,480] ]
Only solution I found is the following:
tempVar = []
HashConst.keys.each_with_index{ |res,idx| tempVar [idx] = [res, 1]}
NewArrayConst = tempVar
Anyone knows a better solution to this and can explain why I cannot get the output I expect from NewArrayConst = HashConst.keys.each{ |res| [res, 1]}. I'm using 2.2.2-p95
Edit:
As many pointed out Hash var name is wrong and misleading, I have updated that to avoid confusion
You need to use map instead of each.
Array#each method does not return the result of the code executed in the block, but instead just returns the array on which each was called, which in your case is the value of hash.keys.
Array#map collects the values returned by block into an array.
hash = {[120,240] => 60, [240,480]=> 30}
p array = hash.keys.map{ |res| [res, 1]}
#=> [[[120, 240], 1], [[240, 480], 1]]
NOTE: Do not name your variable Hash as it is already a well-known class in Ruby. Use lower case hash if need be. Also, avoid camel case for variable names such as NewArrayConst, as Ruby recommends use of snake_case for naming variables - you can refer Ruby Style Guide for more details.
h = {[120,240] => 60, [240,480]=> 30}
val = 1
h.keys.product([val])
#=> [[[120, 240], 1], [[240, 480], 1]]
Have you tried Hash.to_a? Sometimes things are easier than you think.

Accessing values from Dictionaries that are part of an Array in Swift

G'day,
I'm trying to use a for loop to access the values for the same key within an array of dictionaries in Swift.
For example,
let dictionaryOne = [
"name": "Peter",
"age": "42",
"location": "Milwaukee"]
let dictionaryTwo = [
"name": "Paul",
"age": "89",
"location": "Denver"]
let arrayOfDictionaries = [dictionaryOne, dictionaryTwo]
I'm attempting to create a function using a for loop that will output an array containing the values for location i.e. ["Milwaukee", "Denver"]
I have looked at other responses but I can only find how to access the value for "location" straight from the dictionary itself, which would be cumbersome if there were many different dictionaries rather than just two.
Many thanks for any help you can provide!
You can take advantage of the map method, whose purpose is to loop through the array and transform each element into another type:
arrayOfDictionaries.map { (dict: [String : String]) -> String? in
return dict["location"]
}
The closure passed to the map receives an array element, and returns the transformed value - in your case, it retrieves and returns the value for the location key.
You can also use the compact form:
arrayOfDictionaries.map { $0["location"] }
Note that this method returns an array of optional strings, because the dictionary subscript operator always returns an optional. If you need an array of non optionals, then this is the unsafe version:
let x = arrayOfDictionaries.map { $0["location"]! }
Of course if the value for "location" key doesn't exist for an array element, a runtime exception will be raised.
More info about map at the Swift Standard Template Library
The way I see it, you would populate a new array of Strings from the cities listed before.
var locations = [String]()
for dictionary in arrayOfDictionaries{
locations.append(dictionary["location"]!)
}
println(locations)
There are a few ways you could do this. One is to use key-value coding (KVC):
let locations = (arrayOfDictionaries as NSArray).valueForKey("location") as [String]

Filling hash of multi-dimensional arrays in perl

Given three scalars, what is the perl syntax to fill a hash in which one of the scalars is the key, another determines which of two arrays is filled, and the third is appended to one of the arrays? For example:
my $weekday = "Monday";
my $kind = "Good";
my $event = "Birthday";
and given only the scalars and not their particular values, obtained inside a loop, I want a hash like:
my %Weekdays = {
'Monday' => [
["Birthday", "Holiday"], # The Good array
["Exam", "Workday"] # The Bad array
]
'Saturday' => [
["RoadTrip", "Concert", "Movie"],
["Yardwork", "VisitMIL"]
]
}
I know how to append a value to an array in a hash, such as if the key is a single array:
push( #{ $Weekdays{$weekday} }, $event);
Used in a loop, that could give me:
%Weekdays = {
'Monday' => [
'Birthday',
'Holiday',
'Exam',
'Workday'
]
}
I suppose the hash key is the particular weekday, and the value should be a two dimensional array. I don't know the perl syntax to, say, push Birthday into the hash as element [0][0] of the weekday array, and the next time through the loop, push another event in as [0][1] or [1][0]. Similarly, I don't know the syntax to access same.
Using your variables, I'd write it like this:
push #{ $Weekdays{ $weekday }[ $kind eq 'Good' ? 0 : 1 ] }, $event;
However, I'd probably just make the Good/Bad specifiers keys as well. And given my druthers:
use autobox::Core;
( $Weekdays{ $weekday }{ $kind } ||= [] )->push( $event );
Note that the way I've written it here, neither expression cares whether or not an array exists before we start.
Is there some reason that
push #{ $Weekdays{Monday}[0] }, "whatever";
isn’t working for you?

How to get hashes out of arrays in Perl?

I want to write a little "DBQuery" function in perl so I can have one-liners which send an SQL statement and receive back and an array of hashes, i.e. a recordset. However, I'm running into an issue with Perl syntax (and probably some odd pointer/reference issue) which is preventing me from packing out the information from the hash that I'm getting from the database. The sample code below demonstrates the issue.
I can get the data "Jim" out of a hash inside an array with this syntax:
print $records[$index]{'firstName'}
returns "Jim"
but if I copy the hash record in the array to its own hash variable first, then I strangely can't access the data anymore in that hash:
%row = $records[$index];
$row{'firstName'};
returns "" (blank)
Here is the full sample code showing the problem. Any help is appreciated:
my #records = (
{'id' => 1, 'firstName' => 'Jim'},
{'id' => 2, 'firstName' => 'Joe'}
);
my #records2 = ();
$numberOfRecords = scalar(#records);
print "number of records: " . $numberOfRecords . "\n";
for(my $index=0; $index < $numberOfRecords; $index++) {
#works
print 'you can print the records like this: ' . $records[$index]{'firstName'} . "\n";
#does NOT work
%row = $records[$index];
print 'but not like this: ' . $row{'firstName'} . "\n";
}
The nested data structure contains a hash reference, not a hash.
# Will work (the -> dereferences the reference)
$row = $records[$index];
print "This will work: ", $row->{firstName}, "\n";
# This will also work, by promoting the hash reference into a hash
%row = %{ $records[$index] };
print "This will work: ", $row{firstName}, "\n";
If you're ever presented with a deep Perl data structure, you may profit from printing it using Data::Dumper to print it into human-readable (and Perl-parsable) form.
The array of hashes doesn't actually contain hashes, but rather an references to a hash.
This line:
%row = $records[$index];
assigns %row with one entry. The key is the scalar:
{'id' => 1, 'firstName' => 'Jim'},
Which is a reference to the hash, while the value is blank.
What you really want to do is this:
$row = $records[$index];
$row->{'firstName'};
or else:
$row = %{$records[$index];}
$row{'firstName'};
Others have commented on hashes vs hashrefs. One other thing that I feel should be mentioned is your DBQuery function - it seems you're trying to do something that's already built into the DBI? If I understand your question correctly, you're trying to replicate something like selectall_arrayref:
This utility method combines "prepare", "execute" and "fetchall_arrayref" into a single call. It returns a reference to an array containing a reference to an array (or hash, see below) for each row of data fetched.
To add to the lovely answers above, let me add that you should always, always, always (yes, three "always"es) use "use warnings" at the top of your code. If you had done so, you would have gotten the warning "Reference found where even-sized list expected at -e line 1."
what you actually have in your array is a hashref, not a hash. If you don't understand this concept, its probably worth reading the perlref documentation.
to get the hash you need to do
my %hash = %{#records[$index]};
Eg.
my #records = (
{'id' => 1, 'firstName' => 'Jim'},
{'id' => 2, 'firstName' => 'Joe'}
);
my %hash = %{$records[1]};
print $hash{id}."\n";
Although. I'm not sure why you would want to do this, unless its for academic purposes. Otherwise, I'd recommend either fetchall_hashref/fetchall_arrayref in the DBI module or using something like Class::DBI.
Also note a good perl idiom to use is
for my $rowHR ( #records ) {
my %row = %$rowHR;
#or whatever...
}
to iterate through the list.

Resources