intersection of a ruby array and the keys of a hash - arrays

Is it possible to get the intersection of an array and just the keys of a hash?
I know that the & operator returns the intersection of two arrays, but I'd like to use the values instead of the value + key combination.
Let's say, I have an array and a hash :
a1 = [ 'test1', 'test2', 'test3' ]
a2 = { 'test3' => 'value3', 'test4'=>'value4', 'test5'=>'value5' }
is there a way to return value3 from these?

given
arr = ['value1', 'value2', 'value3']
hsh = {:key1 => 'value3', :key2=>'value4', :key3=>'value5'}
you can convert hsh to an array of values with the .values method and use the & operator to compare the hash values with an array.
arr & hsh.values
=> ["value3"]

This is probably the most intuitive way I can think of to do what you're asking:
a1 = [ 'test1', 'test2', 'test3' ]
a2 = { 'test3' => 'value3', 'test4'=>'value4', 'test5'=>'value5' }
(a1 & a2.keys).map { |e| a2[e] }
#=> ["value3"]
That is you want the intersection of a1 and the keys from a2. You can then use map to perform the lookup on each key found in the intersection to return the value.

a1.reduce(nil) {|r, k| r || a2[k]} should do what you're asking.

Related

how to merge values in a list of map in ruby

say I have data structure like List< MAP< String, List>>, I only want to keep the List in map's value,
Like, I want to convert following example:
x = [{"key1" => ["list1", "list1"]}, {"key2" => ["list2", "list2"]},
{"key3" => ["list3", "list3"]}]
to:
y = [["list1", "list1"], ["list2", "list2"], ["list3", "list3"]]
Is there any quick way to do this? Thanks
The quickest thing that comes to mind is to leverage flat_map.
x = [ { "key1" => ["list1", "list1"] },
{ "key2" => ["list2", "list2"] },
{ "key3" => ["list3", "list3"] }]
y = x.flat_map(&:values)
=> [["list1", "list1"], ["list2", "list2"], ["list3", "list3"]]
flat_map is an instance method on Enumerable (https://ruby-doc.org/core-2.6.3/Enumerable.html#method-i-flat_map)
values is an instance method on Hash (https://ruby-doc.org/core-2.6.3/Hash.html#method-i-values)
If you only have 1 key in those hashes then you can do it like this:
y = x.map { |h| h.values[0] }

Ruby mapping array into hash

I have a 2D array with each row like:
['John', 'M', '34']
I want to map into an array of Hash with each hash like:
{:Name=>"John", :Gender=>"M", :Age=>"34"}
Is there an elegant way of doing that?
array_of_rows.map { |n,g,a| { Name: n, Gender: g, Age: a } }
or
array_of_rows.map { |row| %i{Name Gender Age}.zip(row).to_h }
They produce the same result, so pick the one you find clearer. For example, given this input:
array_of_rows = [
['John', 'M', '34'],
['Mark', 'M', '49']
]
either expression will yield this output:
[{:Name=>"John", :Gender=>"M", :Age=>"34"},
{:Name=>"Mark", :Gender=>"M", :Age=>"49"}]
You could try using zip and then to_h (which stands for to hash)
For example:
[:Name, :Gender, :Age].zip(['John', 'M', '34']).to_h
=> {:Name=>"John", :Gender=>"M", :Age=>"34"}
Read more about zip here
And read about to_h here
people = [['John', 'M', '34']]
keys = %i{Name Gender Age}
hashes = people.map { |person| keys.zip(person).to_h }
# => [{:Name=>"John", :Gender=>"M", :Age=>"34"}]
Basically the way I turn combine two arrays into a hash (one with keys, one with values) is to use Array#zip. This can turn [1,2,3] and [4,5,6] into [[1,4], [2,5], [3,6]]
This structure can be easily turned into a hash via to_h
array_of_rows = [
['John', 'M', '34'],
['Mark', 'M', '49']
]
keys = ['Name', 'Gender', 'Age']
[keys].product(array_of_rows).map { |k,v| k.zip(v).to_h }
#=> [{"Name"=>"John", "Gender"=>"M", "Age"=>"34"},
# {"Name"=>"Mark", "Gender"=>"M", "Age"=>"49"}]
or
keys_cycle = keys.cycle
array_of_rows.map do |values|
values.each_with_object({}) { |value, h| h[keys_cycle.next]=value }
do
Here is one more way to do this
array_of_rows = [
['John', 'M', '34'],
['Mark', 'M', '49']
]
keys = [:Name, :Gender, :Age]
array_of_rows.collect { |a| Hash[ [keys, a].transpose] }
#=>[{:Name=>"John", :Gender=>"M", :Age=>"34"}, {:Name=>"Mark", :Gender=>"M", :Age=>"49"}]

Ruby Hash Values is Array, need to convert to string

I have a hash of integers as keys and arrays of strings as values. I need to convert this to a new hash that inverts this relationship with each item from the array of strings in the original hash values becoming a key in the new hash and each original key becoming the associated value. For example:
original = {1 => ['a', 'b', 'c'], 2 => ['g', 'm', 'z']}
new_hash = {'a' => 1, 'b' => 1, 'c' => 1, 'g' => 2, 'm' => 2, 'z' => 2}
I'm struggling to extract the items from the original array values. It's easy enough to do
original.each { |k, v| new_hash[v] = k }
but this keeps the original array as the new key. I've tried doing something like
original.each { |k, v| new_hash[v.each { |i| i }] = k }
but this also returns the original array for some reason.
Another one, via Array#product:
original.flat_map { |k, v| v.product([k]) }.to_h
#=> {"a"=>1, "b"=>1, "c"=>1, "g"=>2, "m"=>2, "z"=>2}
original.flat_map { |k, vs| vs.map { |v| {v => k} } }.reduce(&:merge)
the below snippet will give what you want, but let me think on a more readable and elegant solution.
newhash = {}
original.each do |k,v|
v.each do |v2|
newhash[v2] = k
end
end
#=> {1=>["a", "b", "c"], 2=>["g", "m", "z"]}
newhash
#=> {"a"=>1, "b"=>1, "c"=>1, "g"=>2, "m"=>2, "z"=>2}
Your approach is close. You'll have to iterate each element in the values array when assigning the new key/value pair to the newHash
newHash = {}
original.each { |k, v| v.each {|i| newHash[i] = k}}
original.map { |number, ary| Hash[ary.map { |char| [char, number] }] }.reduce(&:merge)

Convert array of arrays to array of hash

I have following array of arrays in Perl that are getting as multiple rows in database.
$arrayref = [
[ 1, "name1", "name2" ],
[ 2, "name3", undef ],
[ 3, "name5", "name6" ],
[ 4, "name10", undef ],
];
I want to make this as an array of hashes like this
my #array = (
{ id => 1, name => "name1", l_name => "name2" },
{ id => 2, name => "name3", l_name => undef },
{ id => 3, name => "name5", l_name => "name6" },
{ id => 4, name => "name10", l_name => undef },
);
You can use map {} to transform array references to hash references,
my #cols = qw(id name l_name);
my #array = map { my %h; #h{#cols} = #$_; \%h } #$arrayref;
or
use List::MoreUtils qw( zip );
my #cols = qw(id name l_name);
my #array = zip(\#cols, #$arrayref);
I have following array of arrays in Perl that are getting as multiple rows in database
You are presumably calling
$sth->fetchall_arrayref();
If instead you use an empty anonymous hash as the first parameter
$sth->fetchall_arrayref( {} );
then DBI will return the data in the format you want as an array of hashes
The DBI documentation describes it here
If $slice is a hash reference, fetchall_arrayref fetches each row as a hash reference. If the $slice hash is empty then the keys in the hashes have whatever name lettercase is returned by default. (See FetchHashKeyName attribute.) If the $slice hash is not empty, then it is used as a slice to select individual columns by name. The values of the hash should be set to 1. The key names of the returned hashes match the letter case of the names in the parameter hash, regardless of the FetchHashKeyName attribute.
For example, to fetch all fields of every row as a hash ref:
$tbl_ary_ref = $sth->fetchall_arrayref({});

Array in value of hash perl

Is it possible to assign the reference of an array as the value in the key : value pair of a hash table in perl?
Yes it is. Create a reference to the array by using backslash:
$hash{key} = \#array;
Note that this will link to the actual array, so if you perform a change such as:
$array[0] = "foo";
That will also mean that $hash{key}[0] is set to "foo".
If that is not what you want, you may copy the values by using an anonymous array reference [ ... ]:
$hash{key} = [ #array ];
Moreover, you don't have to go through the array in order to do this. You can simply assign directly:
$hash{key} = [ qw(foo bar baz) ];
Read more about making references in perldoc perlref
Yes. See http://perlmonks.org/?node=References+quick+reference for some basic rules for accessing such data structures, but to create it, just do one of these:
%hash = ( 'somekey' => \#arrayvalue );
$hash{'somekey'} = \#arrayvalue;
%hash = ( 'somekey' => [ ... ] );
use Data::Dumper; #name=('5/17',
'5/17','5/17','5/17','5/17','5/17','5/17','5/17'); #status_flags=('U
H L','U C','U H L','U C','U C','U H L','U C', 'U H L');
#ip_address=('192.168.0.11','192.168.0.2','192.168.0.13','192.168.0.0','192.168.0.3','192.168.0.12','192.168.0.4','192.168.0.14'); #dp_id=('0','0','0','0','0','0','0','0');
#ip_prefix_length=('32','32','32','24', '32', '32','32','32');
for ($value=0;$value<=5;$value++) {
$keyvals{'Response'}{'brocade-extension-ip-route'}{'extension-ip-route'}={'name'=>"$name[$value]"};
$keyvals{'Response'}{'brocade-extension-ip-route'}{'extension-ip-route'}={'dp-id'=>"$dp_id[$value]"};
$keyvals{'Response'}{'brocade-extension-ip-route'}{'extension-ip-route'}={'ip-address'=>"$ip_address[$value]"};
$keyvals{'Response'}{'brocade-extension-ip-route'}{'extension-ip-route'}={'ip-prefix-length'=>"$ip_prefix_length[$value]"};
$keyvals{'Response'}{'brocade-extension-ip-route'}{'extension-ip-route'}={'ip-gateway'=>'*'};
}
print Dumper \%keyvals;
Each array value assign into hash value. $var1= {
'Response' => {
'extension-ip-route' => {
'status-flags' => 'U H L '
,
'ip-gateway' => '*',
'name' => '0/2',
'ip-address' => '192.168.20.11',
'dp-id' => '0',
'ip-prefix-length'=>'32'
}
}
};

Resources