I am trying to match key value pairs in an array and print them in a clear format:
array = [
{
'name' => 'Tom',
'age' => '31',
'weight' => '180'
},
{
'name' => 'Jane',
'age' => '24',
'weight' => '110'
}
]
array.each do |key, value|
if #{key} == "name"
puts "Name_is=#{key}"
else
puts "#{key}=#{value}"
end
end
This results in:
Name_is={"name"=>"Tom", "age"=>"31", "weight"=>"180"}
{"name"=>"Tom", "age"=>"31", "weight"=>"180"}=
Name_is={"name"=>"Jane", "age"=>"24", "weight"=>"110"}
{"name"=>"Jane", "age"=>"24", "weight"=>"110"}=
Expected result is:
Name_is=Tom
age=31
weight=180
Name_is=Jane
age=24
weight=110
What am I not doing right?
You have an array of hashes, you need to make a nested loop which loops over the array and, for each hash in the array, loops on the key/value pairs:
array.each do |hash|
hash.each do |key, value|
if key == "name"
puts "Name_is=#{key}"
else
puts "#{key}=#{value}"
end
end
end
Also I'm not sure why you have if #{key} == "name" while you can simply have if key == "name".
I think this is a Ruby-like solution:
array = [
{
'name' => 'Tom',
'age' => '31',
'weight' => '180'
},
{
'name' => 'Jane',
'age' => '24',
'weight' => '110'
}
]
array.each do |hash|
hash['Name_is'] = hash.delete 'name'
hash.each do |key, value|
puts "#{key}=#{value}"
end
end
Related
I have this collection
1 => {#27
+"id": 1
+"name": "Zel"
+"age": "43"
}
2 => {#28
+"id": 2
+"name": "Kol"
+"age": "56"
}
3 => {#29
+"id": 3
+"name": "Mil"
+"age": "32"
}
and I would like to return an array with the key values as a string like this:
[
'id',
'name',
'age',
]
Can someone help me with that, please?
use array_keys :
$keys = array_keys($collection->first());
Laravel collection has a keys() method you could simply use it like this:
$keys = $collection->keys();
$get = $keys->all();
It is all clearly written in the Laravel Documentation
EDIT
After looking at your edit, my first consideration would be that if your collection is consistent you could get the first one and subsequently get the keys from there on:
$keys = $collection->first();
$get = $keys->keys()->all();
Or simply put $collection->first()->keys()->all();
EDIT
Here is how i was able to reproduce your problem:
$collection = collect([
[
'id' => 1,
'name' => 'Zel',
'age' => 43
],
[
'id' => 2,
'name' => 'Kol',
'age' => 56
],
[
'id' => 3,
'name' => 'Mil',
'age' => 32
],
]);
$keys = collect($collection->first())->keys()->all();
Here is the Result I got:
array:3 [▼
0 => "id"
1 => "name"
2 => "age"
]
If it still returns a collection or an object based on your last comment, you could try any one of these:
$keys = $keys->toArray();
$keys = collect($keys)->toArray();
One of the things that I really like about Active Record is its named scopes and being able to chain scopes together to build expressive queries.
What would be a similar way to achieve this with plain Ruby Enumerables/Arrays, ideally without monkey-patching Enumerable or Array in any dangerous way?
For example:
### ActiveRecord Model
class User < ActiveRecord::Base
scope :customers, -> { where(:role => 'customer') }
scope :speaking, ->(lang) { where(:language => lang) }
end
# querying
User.customers.language('English') # all English customers
### Plain-Ruby Array
module User
class << self
def customers
users.select { |u| u[:role] == 'customer' }
end
def speaking(lang)
users.select { |u| u[:language] == lang }
end
private
def users
[
{:name => 'John', :language => 'English', :role => 'customer'},
{:name => 'Jean', :language => 'French', :role => 'customer'},
{:name => 'Hans', :language => 'German', :role => 'user'},
{:name => 'Max', :language => 'English', :role => 'user'}
]
end
end
end
User.customers # all customers
User.language('English') # all English speakers
# how do I achieve something similar to User.customers.language('English') ...?
I know I can build a method customers_with_language inside the module, but I'm looking for a general way to solve this with any number of "scopes".
Here is a crude implementation of a ScopableArray, which inherits an Array:
class ScopableArray < Array
def method_missing(method_sym, *args)
ScopableArray.new(select { |u| u[method_sym] == args[0] } )
end
end
When this class receives a method it does not identify, it assumes you want to filter it according to a field of the method's name with the argument's value:
users = ScopableArray.new([
{:name => 'John', :language => 'English', :role => 'customer'},
{:name => 'Jean', :language => 'French', :role => 'customer'},
{:name => 'Hans', :language => 'German', :role => 'user'},
{:name => 'Max', :language => 'English', :role => 'user'}
])
users.role('customer')
# => [{:name=>"John", :language=>"English", :role=>"customer"}, {:name=>"Jean", :language=>"French", :role=>"customer"}]
users.role('customer').language('English')
# => [{:name=>"John", :language=>"English", :role=>"customer"}]
You can also look at ActiveRecord's implementation pattern for a more elaborate scheme where you can define scopes by passing a name and a callable block, something like this:
class ScopableArray2 < Array
class << self
def scope(name, body)
unless body.respond_to?(:call)
raise ArgumentError, 'The scope body needs to be callable.'
end
define_method(name) do |*args|
dup.select! { |x| body.call(x, *args) }
end
end
end
end
Then you can do something like this:
class Users < ScopableArray2
scope :customers, ->(x) { x[:role] == 'customer' }
scope :speaking, ->(x, lang) { x[:language] == lang }
end
users = Users.new([
{:name => 'John', :language => 'English', :role => 'customer'},
{:name => 'Jean', :language => 'French', :role => 'customer'},
{:name => 'Hans', :language => 'German', :role => 'user'},
{:name => 'Max', :language => 'English', :role => 'user'}
])
users.customers.speaking('English')
# => [{:name=>"John", :language=>"English", :role=>"customer"}]
I'm trying to sort my AoH which looks like this:
$VAR1 = [
{
'Name' => 'John',
'Lastname' => 'Derp',
'Organization' => 'Finance',
'OfficeNR' => '23',
'ID' => '145'
},
{
'Name' => 'Kate',
'Lastname' => 'Herp',
'Organization' => 'HR',
'OfficeNR' => '78',
'ID' => '35'
},
{
'Name' => 'Jack',
'Lastname' => 'Serp',
'Organization' => 'Finance',
'OfficeNR' => '23',
'ID' => '98'
}
];
What I'm trying to do is to filter my output using keys from AoH, for example print out only those who have 'Organization' => 'Finance'.
I've tried to solve it using new array:
my #SortedAoH = sort { {Organization=>{'Finance'}} } #AoH;
But it doesn't work.
What you want is grep, not sort. You are getting the basic syntax of equivalence checking wrong as well.
Anyway, the filter is:
my #finance_orgs = grep { $_->{'Organization'} eq 'Finance' } #AoH;
The #finance_orgs variable will now only include the ones with Organization set to Finance.
Just an explanation of the pieces:
The $_ variable is the variable that gets assigned whenever the value is implied in a block, such as in grep or map or in a for loop without an explicitly named variable.
$_->{'Organization'} performs a hash lookup on the hash as it iterates through each entry in your array.
eq is the operator used to test for string equivalence (as opposed to == which tests for numeric equivalence).
I have a hash whose keys is a string and key is array(the complication is that the array is defined in the square bracket), So my hash is like this..
model = {
'add' => [
{'name' => 'abc1', 'value' => 'def' },
{'name' => 'abc2', value => 'ghi'}
],
'remove' => [
{'name' => 'abc1', 'value' => 'def' },
{'name' => 'abc2', value => 'ghi'}
]
};
So what I am trying to achive is that when I try to iterate through the hashes of array
model->{add} as
print $_->{name} foreach(model->{add})
it doesnt work.
I guess this is because the array is in [] instead of ().
Considering the input cannot be changed. please let me know how to get through this...
$model = { 'add' => [ {'name' => 'abc1', 'value' => 'def' },
{'name' => 'abc2', 'value' => 'ghi'} ],
'remove' => [ {'name' => 'abc1', 'value' => 'def' },
{'name' => 'abc2', 'value' => 'ghi'} ] };
print $_->{name} foreach( #{ $model->{add} } );
You have a 3-level nested structure: A HashRef containing ArrayRefs containing HashRefs.
my $model = {
'add' => [
{
'name' => 'abc1',
'value' => 'def'
}, {
'name' => 'abc2',
value => 'ghi'
}
],
'remove' => [
{
'name' => 'abc1',
'value' => 'def'
}, {
'name' => 'abc2',
value => 'ghi'
}
]
};
To access those nested arrays and hashes, you need to dereference them, by adding % or # in front of it, depending on whether it is a hash or array.
my $arrayref = $model->{add};
foreach my $hashref (#$arrayref) {
print $hashref->{name}, "\n";
}
The statement:
print $_->{name} foreach(model->{add})
Does not work because model is a bareword, not a variable. If you have these two pragmas in your code:
use strict;
use warnings;
You will not be able to make mistakes like this. warnings will tell you:
Unquoted string "model" may clash with future reserved word at ...
Name "main::model" used only once: possible typo at ...
Use of uninitialized value in print at ...
And strict will tell you:
Can't use bareword ("model") as a HASH ref while "strict refs" in use at ...
However, if you do not have those two pragmas enabled, Perl will happily print the empty string and be silent about the whole thing. Which makes the mistake rather hard to detect.
The correct way to handle this is to grab the correct scalar value from the hash, and dereference it using the correct sigil. If you look at the key 'add':
'add' => [
You'll see that it has an array reference stored in it, which means the sigil to use is #. You'll need support curly braces to disambiguate the references. Also, you have to refer to your variable as $model.
print $_->{name} for #{ $model->{add} };
Which is the same as
my $adds = $model->{add};
print $_->{name} for #$adds;
First and foremost use use strict; use warnings;
The scalar model should be written as
my $model = { 'add' => [ {'name' => 'abc1', 'value' => 'def' }, {'name' => 'abc2', value => 'ghi'} ], 'remove' => [ {'name' => 'abc1', 'value' => 'def' }, {'name' => 'abc2', value => 'ghi'} ] };
and
print $_->{name} foreach( ( #{ $model->{ add } } ) );
How do you get the size of the following array of hashes?
I thought this would do it, but it did not work...
print Dumper scalar $item->{'detail'};
$VAR1 = [
{ 'content' => undef, 'name' => 'entree', 'url_name' => 'entree' },
{ 'content' => undef, 'name' => 'dessert', 'url_name' => 'desert' },
{ 'content' => undef, 'name' => 'drink', 'url_name' => 'drink' }
];
Or how can I print all the url_name (entree, desert, drink) in the array of hashes without knowing the size?
You have an array reference. To get the size of the referenced array, first dereference the reference:
print scalar #{$item->{'detail'}};
And to list the URLs:
my $v = [
{ 'content' => undef, 'name' => 'entree', 'url_name' => 'entree' },
{ 'content' => undef, 'name' => 'dessert', 'url_name' => 'desert' },
{ 'content' => undef, 'name' => 'drink', 'url_name' => 'drink' }
]; # or $v = $item->{'detail'};
foreach my $h (#$v) {
print $h->{url_name}, "\n";
}
I'm not sure why you think you need the array size in order to print the url_name values. Nonetheless, here's how it works.
use strict;
use warnings;
use Data::Dumper;
my $v = [ # note that this is a scalar value
{ 'content' => undef, 'name' => 'entree', 'url_name' => 'entree' },
{ 'content' => undef, 'name' => 'dessert', 'url_name' => 'desert' },
{ 'content' => undef, 'name' => 'drink', 'url_name' => 'drink' }
];
my $item = { detail => $v }; # recreate your structure $item->{detail}
my $size = #$v; # this is how its done with $v
my $size2 = #{ $item->{detail} }; # and with your original structure
my #x = map $_->{url_name}, #$v; # extract url_name values
print Dumper \#x;
As you see, $item->{detail} and $v are identical. When you feed this scalar value directly (through the scalar function, which does nothing in this case) to Dumper, you get the printed value seen in $v above. All that scalar does is change the context used with print and enforce a scalar context rather than list context. We can do the same thing by using scalar assignment ($size and $size2).
When using the original structure, you need to use the #{ } brackets to clarify for perl that what is inside them is an array ref.
As you see, extracting the values is easily done with a map statement. It acts as a loop, iterating over all the values in #$v (or #{ $item->{detail} }), returning for each value the statement $_->{url_name}.