I'm having a problem trying to get objects from an array where a given hash might either have a specific property and a specific value, or a nested hash which potentially can too.
Is there a method for returning the specific hash that has the key I need OR RECURSE when it doesn't?
Example: I have this completely made-up structure:
the_array = [
{
:is_father => true,
:seek_this => "01"
},
{
:is_uncle => false,
:children => [
{
:seek_this => "09"
},
{
:seek_this => "2a"
}
]
},
{
:random_property=> 3,
:children => {
:random_er => true,
:children => [
{
:is_father => false,
:children => [
{
:seek_this => "3b"
},
{
:seek_this => "h1"
}
]
}
]
}
}
]
And after calling
the_array
.methodThatIDoNotKnow { |x| !x.seek_this.nil? }
.each do |hash_i_need|
//operate on hash somehow
hash_i_need.seek_this = 0xDEADBEEF
end
This is what I would expect to have happened:
the_array = [
{
:some_key => true,
:seek_this => 0xDEADBEEF
},
{
:some_other_key => false,
:children => [
{
:seek_this => 0xDEADBEEF
},
{
:seek_this => 0xDEADBEEF
}
]
},
{
:random_key: 3,
:children => {
:random_er => true,
:children => [
{
:is_father => false,
:children => [
{
:seek_this => 0xDEADBEEF
},
{
:seek_this => 0xDEADBEEF
}
]
}
]
}
}
]
I understand this is something that I can code myself, I'm just wondering if I need to or there is functionality for this kind of search out of the box.
Thanks!
there is a fetch method on hash but it doesn't recurse through object
you could use this answer or there are many deep fetch examples out there. good luck!
Related
I have an array that I'm wanting to recursively turn into a collection and to use the collection as object values.
I would like to use the collection object in similar ways that eloquent is used rather than using $contact['name'] and being able to use $collection->contacts->each vs foreach $collection->contacts .....)
$collection->contacts->each(function ($contact) {
// ability to use $contact->name (and not have to use $contact['name'])
});
Collection Macro:
Collection::macro('recursive', function () {
return $this->map(function ($value) {
if (is_array($value)) {
return (object)$value;
}
if (is_object($value)) {
return collect($value)->recursive();
}
return $value;
});
});
Example:
public function test_it_can_recursively_convert_array_to_collection()
{
$data = [
[
'name' => 'Michael Scott',
'emails' => [
'mscott#dundermifflin.com',
'michaelscarn#dundermifflin.com',
],
'contacts' => [
[
'name' => 'Dwight Schrute',
'emails' => [
'dschrute#dundermifflin.com',
],
],
[
'name' => 'Jim Halpert',
'emails' => [
'jhalpert#dundermifflin.com',
],
],
],
],
];
$collection = collect($data)->recursive();
$this->assertInstanceOf(Collection::class, $collection);
$collection->each(function ($item) {
$this->assertEquals('Michael Scott', $item->name);
$item->contacts->each(function ($contact) {
$this->assertNotNull($contact->name);
});
});
}
The original collection map works (e.g. $collection->each .... $item->name) but I can't seem to set convert the nested arrays to objects and get the object values.
Error: Call to a member function each() on array
Illuminate\Support\Collection^ {#632
#items: array:1 [
0 => {#13
+"name": "Michael Scott"
+"emails": array:2 [
0 => "mscott#dundermifflin.com"
1 => "michaelscarn#dundermifflin.com"
]
+"contacts": array:2 [
0 => array:2 [
"name" => "Dwight Schrute"
"emails" => array:1 [
0 => "dschrute#dundermifflin.com"
]
]
1 => array:2 [
"name" => "Jim Halpert"
"emails" => array:1 [
0 => "jhalpert#dundermifflin.com"
]
]
]
}
]
}
I request a web service and get a JSON response:
{
"timestamp" : "2019-06-11T08:04:35Z",
"version" : "0.5",
"document" : [
{
"href" : "http://opac.sub.uni-goettingen.de/DB=1/PPNSET?PPN=1629107239",
"item" : [
{
"href" : "http://opac.sub.uni-goettingen.de/DB=1/PPNSET?PPN=1629107239",
"label" : "40 623 a",
"id" : "http://uri.gbv.de/document/opac-de-7:epn:3421084610",
"available" : [
{
"service" : "presentation"
}
],
"unavailable" : [
{
"service" : "loan"
},
{
"service" : "interloan"
}
]
},
{
"href" : "http://opac.sub.uni-goettingen.de/DB=1/PPNSET?PPN=1629107239",
"label" : "40 623 b",
"id" : "http://uri.gbv.de/document/opac-de-7:epn:342108467X",
"available" : [
{
"service" : "presentation"
}
],
"unavailable" : [
{
"service" : "loan"
},
{
"service" : "interloan"
}
]
}
],
"id" : "http://uri.gbv.de/document/opac-de-7:ppn:1629107239"
}
],
"institution" : {
"href" : "http://www.sub.uni-goettingen.de",
"content" : "Niedersächsische Staats- und Universitätsbibliothek Göttingen",
"id" : "http://uri.gbv.de/organization/isil/DE-7"
}
}
Then I parse the JSON with Perls Dumper::Data module:
my $data = decode_json($resultJson);
print Dumper($data);
It looks like:
$VAR1 = {
'document' => [
{
'item' => [
{
'available' => [
{
'service' => 'presentation'
}
],
'id' => 'http://uri.gbv.de/document/opac-de-7:epn:3421084610',
'href' => 'http://opac.sub.uni-goettingen.de/DB=1/PPNSET?PPN=1629107239',
'label' => '40 623 a',
'unavailable' => [
{
'service' => 'loan'
},
{
'service' => 'interloan'
}
]
},
{
'available' => [
{
'service' => 'presentation'
}
],
'unavailable' => [
{
'service' => 'loan'
},
{
'service' => 'interloan'
}
],
'id' => 'http://uri.gbv.de/document/opac-de-7:epn:342108467X',
'label' => '40 623 b',
'href' => 'http://opac.sub.uni-goettingen.de/DB=1/PPNSET?PPN=1629107239'
}
],
'id' => 'http://uri.gbv.de/document/opac-de-7:ppn:1629107239',
'href' => 'http://opac.sub.uni-goettingen.de/DB=1/PPNSET?PPN=1629107239'
}
],
'institution' => {
'content' => "Nieders\x{e4}chsische Staats- und Universit\x{e4}tsbibliothek G\x{f6}ttingen",
'id' => 'http://uri.gbv.de/organization/isil/DE-7',
'href' => 'http://www.sub.uni-goettingen.de'
},
'timestamp' => '2019-06-11T08:04:35Z',
'version' => '0.5'
};
I would like to display the availability of each item, but I'm having a hard time iterating through the arrays inside the objects. My actual code looks like:
my $availability = $data->{document}[0]->{item}[0]->{available};
foreach my $key (#{$availability}) {
if (($key->{'service'}) eq "loan") {
print $rueckgabe = "Loan: available.\n";
} elsif (($key->{'service'}) eq "presentation") {
print $rueckgabe = "Presentation: available.\n";
} elsif (($key->{'service'}) eq "interloan") {
print $rueckgabe = "ILL: available.\n";
}
}
My expected result would be:
Item 1: Loan: available.
Item 2: Loan: available.
Iterate over the items, for each item, iterate over the availabilities.
for my $i (0 .. $#{ $data->{document}[0]{item} }) {
print 'Item ', $i + 1, ': ';
for my $availability ($data->{document}[0]{item}[$i]{available}) {
for my $key (#$availability) {
print { interloan => 'ILL' }->{ $key->{service} } || ucfirst $key->{service},
": available\n";
}
}
}
I have an array A that looks like this:
A = [ { "id" => "1234", "name" => "audi", "isCool" => false },
{ "id" => "5678", "name" => "acura", "isCool" => false },
{ "id" => "9101112", "name" => "bentley", "isCool" => true },
{ "id" => "13141516", "name" => "rollsroyce", "isCool" => true },
{ "id" => "17181920", "name" => "toyota", "isCool" => true } ]
and I have an array B that looks like this:
B = ["1234", "13141516”]
I am trying to select only elements from array A that match array A's ids with Array Bs elements.
So the returned results I would like is:
C = [ { "id" => "1234", "name" => "audi", "isCool" => false },
{ "id" => "13141516", "name" => "rollsroyce", "isCool" => true } ]
Is there an easy way to go about this?
I have currently tried this but obviously not a good idea:
a.select {|x| x['id'] == B.first || B.last}
But obviously this is not dynamic, because what if I had 3 or 4 elements in array B.
A.select { |x| B.include?(x['id']) }
I have an array like this:
[
{:game_id=>546012, :period=>:fg, :stat_name=>:hits, :result=>12, :team_id=>1104},
{:game_id=>546012, :period=>:fg, :stat_name=>:errors, :result=>1, :team_id=>1104},
{:game_id=>546012, :period=>:fg, :stat_name=>:hits, :result=>9, :team_id=>1103},
{:game_id=>546012, :period=>:fg, :stat_name=>:errors, :result=>3, :team_id=>1103}
]
How can turn it into an array of items like this:
{ 546012 => { :hits => { :fg => { 1104 => 12,
1103 => 9 } }
:errors => { :fg => { 1104 => 1,
1103 => 3 } } }
First, create a hash organized by :game_id
{ 546012 => {{
{:period=>:fg, :stat_name=>:hits, :result=>12, :team_id=>1104},
{:period=>:fg, :stat_name=>:errors, :result=>1, :team_id=>1104},
{:period=>:fg, :stat_name=>:hits, :result=>9, :team_id=>1103},
{:period=>:fg, :stat_name=>:errors, :result=>3, :team_id=>1103}
]}
Then group by :stat_name
{ 546012 => [
{:hits => [
{:period=>:fg, :result=>12, :team_id=>1104},
{:period=>:fg, :result=>9, :team_id=>1103}],
:errors => [
{:period=>:fg, :result=>1, :team_id=>1104},
{:period=>:fg, :result=>3, :team_id=>1103}
]}
]}
Then group by period:
{ 546012 => [
{:hits => [
:fg => [{:result=>12, :team_id=>1104},
{:result=>9, :team_id=>1103}]
]}
]},
:errors => [
:fg => [{:result=>1, :team_id=>1104},
{:result=>3, :team_id=>1103}]
]}
]}
Lastly, group by :team_id and associate each one to its :result.
{ 546012 => [
{:hits => [
:fg => [1104 => 12, 1103 => 9]
]},
:errors => [
:fg => [1104 => 1, 1103 => 3]
]}
]}
As for how to create these groupings, I will leave it as an exercise to you.
One possible method is to loop through each item and create a new copy of the object that stores these new mappings. For instance, if we have this object:
foods = {
{:food => lemon, :taste => sour},
{:food => pretzel, :taste => salty},
{:food => pretzel, :taste => sweet}
}
We could group by foods like (pseudocode):
newfoods = {};
foreach item in foods:
newfoods[ item.food ].push( item.taste );
And end up with
newfoods = [
{ lemon => [sour] },
{ pretzel => [sweet, salty] }
]
The best option you can do is flatten it.
Credits go to this question.
Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Questions concerning problems with code you've written must describe the specific problem — and include valid code to reproduce it — in the question itself. See SSCCE.org for guidance.
Closed 9 years ago.
Improve this question
In Perl, from the below hash:
{
'item3' => {
'floors' => [ 'a', 'b', 'c' ]
},
'item1' => [ 'special' ]
'item2' => {
'books' => {
'topics' => [ 'epics' ]
},
'sports' => [ 'tennis' ]
},
'item5' => {
'groups' => {
'teams' => [ 'x', 'y' ]
}
},
'offers' => {
'list' => [ 'bags' ]
}
}
Need to parse only last values in each sub level of hash where it is always be an array.
Only final child entries(array values) need to be listed.
Expecting the output in one single array:
[ 'a', 'b', 'c', 'special', 'epics', 'tennis', 'x', 'y', 'bags' ]
no idea how to proceed....please help me to get rid of this.
Advance Thanks!!!!
Recursion assumes that data structure consists of hashes and arrays only, and array elements are not references,
use strict;
use warnings;
use Data::Dumper;
my %h;
#h{ 1..5 } = (
{ 'item3' => { 'floors' => [ 'a', 'b', 'c' ] } },
{ 'item1' => [ 'special' ] },
{ 'item2' => {
'books' => { 'topics' => [ 'epics' ] },
'sports' => [ 'tennis' ]
}},
{ 'item5' => { 'groups' => { 'teams' => [ 'x', 'y' ] } } },
{ 'offers' => { 'list' => [ 'bags' ] } },
);
print Dumper [ arrvals(\%h) ];
sub arrvals {
my ($ref) = #_;
return ref($ref) eq "ARRAY"
? #$ref
: map arrvals($_), values %$ref;
}