Perl generating hash of complex records - arrays

The big problem that I can't seem to figure out.
I need to input into this complex hash (array?):
my $raterequest =
{
Shipment =>
{
Shipper =>
{
(static data here)
},
ShipTo =>
{
(static data here too)
},
Package =>
[
{
PackagingType =>
{
Code => '02',
Description => 'Package'
},
PackageWeight =>
{
UnitOfMeasurement =>
{
Code => 'LBS'
},
Weight => $boxWt
},
},
{
PackagingType =>
{
Code => '02',
Description => 'Package'
},
PackageWeight =>
{
UnitOfMeasurement =>
{
Code => 'LBS'
},
Weight => $boxWt
},
}
],
}
};
What I need to input is everything inside the Package array.
I have an LoH that generates an output like this:
my %carton_specs =
(
25 => {
boxQty => 25,
boxWt => 4,
boxNo => 2
},
50 => {
boxQty => 50,
boxWt => 8,
boxNo => 17
},
);
Where I need to repeat the anonymous array inside Package
{
PackagingType =>
{
Code => '02',
Description => 'Package'
},
PackageWeight =>
{
UnitOfMeasurement =>
{
Code => 'LBS'
},
Weight => $boxWt
},
},
times the number returned from $boxNo. The only variable that changes in that is the Weight => $boxWt
Please excuse anything that I might have named wrong. I have been fighting with this for 2 days and my head is exploding.

It sounds to me like you are looking for push plus the information from perlreftut (plus maybe the .. range operator). I hope I understood your specifications correctly:
use warnings;
use strict;
use Data::Dump;
my $raterequest = {
Shipment => {
Package => [ ],
} };
my %carton_specs = (
25 => { boxQty => 25, boxWt => 4, boxNo => 2 },
50 => { boxQty => 50, boxWt => 8, boxNo => 17 },
);
for my $carton (sort keys %carton_specs) {
for ( 1 .. $carton_specs{$carton}{boxNo} ) {
push #{ $raterequest->{Shipment}{Package} }, {
PackagingType => {
Code => '02',
Description => 'Package',
},
PackageWeight => {
UnitOfMeasurement => { Code => 'LBS' },
Weight => $carton_specs{$carton}{boxWt},
},
};
}
}
dd $raterequest;
Output:
{
Shipment => {
Package => [
{
PackageWeight => { UnitOfMeasurement => { Code => "LBS" }, Weight => 4 },
PackagingType => { Code => "02", Description => "Package" },
},
{
PackageWeight => { UnitOfMeasurement => { Code => "LBS" }, Weight => 4 },
PackagingType => { Code => "02", Description => "Package" },
},
{
PackageWeight => { UnitOfMeasurement => { Code => "LBS" }, Weight => 8 },
PackagingType => { Code => "02", Description => "Package" },
},
# ... omit 16 repetitions of the previous hashref ...
],
},
}

Related

Empty Array is being returned before PromiseAll is resolved when used in useEffect method

I am iterating through a multidimensional array then pushing my data to a new array. When I log my array using the 'then' chain it logs empty. Not sure I am goin about this the proper way.
Array.js
export const Cars = [
{
type: "A",
cars: [
{ name: "buick", id: "1259263" },
{ name: "ford", id: "1299830" },
{ name: "audi", id: "0181545" },
{ name: "gmc", id: "0016024" },
],
},
{
type: "B",
cars: [
{ name: "mazada", id: "1306193" },
{ name: "chevy", id: "1374540" },
{ name: "nissan", id: "1419526" },
{ name: "toyota", id: "1333007" },
],
},
{
type: "C",
cars: [
{ name: "bmw", id: "1259297" },
{ name: "porsche", id: "1305493" },
{ name: "tesla", id: "1042547" },
{ name: "mercedes", id: "1012982" },
],
},
];
CarComponent.js
...
export const CarComponent = () => {
const myArr = [];
useEffect(() => {
const fetchList = () => {
Promise.all(
Cars.map((car) => {
return car.cars.map((id) => {
return new Promise((resolve) => {
fetch(`/api/=${id.id}`).then((response) => {
return new Promise(() => {
response.json().then((id) => {
console.log(id); //<----returns normal
myArr.push(id);
resolve();
});
});
});
});
});
}),
).then(() => {
console.log("myArr", myArr); //<-----array is empty?
})
};
fetchList();
}, []);
...
Look at
Promise.all(
Cars.map((car) => {
return car.cars.map((id) => {
The item being returned from the mapper function is not a Promise, but an array - the return car.cars.map needs to be changed to a Promise.
You should also avoid the explicit Promise construction antipattern.
const fetchList = () => {
Promise.all(
Cars.map(({ cars }) => Promise.all(
cars.map(({ id }) =>
fetch(`/api/=${id}`)
.then(res => res.json())
.then((result) => myArr.push(result))
)
))
).then(() => {
console.log("myArr", myArr);
})
};
Another option, rather than pushing to an external array:
const fetchList = () => {
Promise.all(
Cars.map(({ cars }) => Promise.all(
cars.map(({ id }) =>
fetch(`/api/=${id}`)
.then(res => res.json())
)
))
).then((results) => {
console.log("myArr", results.flat());
})
.catch(handleErrors); // don't forget this part
};

Style cell based on values - Reactabular

I would like to implement styling for cells based on values. If a cell has a value within a range, it should have different background colors.
Here is my implementation of the child component which just gets me the columns and does the sort.
import React, {Component} from 'react';
import {connect} from 'react-redux';
import {sortColName} from '../../actions/index';
class DashboardColumns extends Component {
componentDidMount() {
this.props.onRef(this);
}
componentWillUnmount() {
this.props.onRef(undefined);
}
columnClick = (dataField) => {
const sortField = {
sortColName: dataField,
sortDir: this.props.sortColDir === 'asc' ? 'desc' : 'asc',
};
this.props.sortColName(sortField);
};
sortFormatter = (label, column) => {
if (column === this.props.sortCol) {
if (this.props.sortColDir === 'asc') {
return <i><span className="glyphicon glyphicon-triangle-top" />{label}</i>;
} else return <i><span className="glyphicon glyphicon-triangle-bottom" />{label}</i>;
}
return label;
};
percentageFormatter = cell => (<span>{cell} %</span>);
styleFormatter = (cell) => {
if (cell >= 95) {
return <span className="green-background">{cell}</span>;
} else if (cell < 95 && cell > 79) {
return <span className="yellow-background">{cell}</span>;
}
return <span className="red-background">{cell}</span>;
};
columns = [
{
property: 'database_name',
header: {
label: 'Database Name',
formatters: [label => this.sortFormatter(label, 'db_name')],
transforms: [
property => ({
onClick: () => this.columnClick('db_name')
})
]
}
}, {
property: 'target_address',
header: {
label: 'Target Address',
formatters: [label => this.sortFormatter(label, 'target_address')],
transforms: [
property => ({
onClick: () => this.columnClick('target_address')
})
]
}
}, {
property: 'db_type',
header: {
label: 'Database Type',
formatters: [label => this.sortFormatter(label, 'db_type')],
transforms: [
property => ({
onClick: () => this.columnClick('db_type')
})
]
}
}, {
property: 'environment_classification',
header: {
label: 'Environment',
formatters: [label => this.sortFormatter(label, 'environment_classification')],
transforms: [
property => ({
onClick: () => this.columnClick('environment_classification')
})
]
}
}, {
property: 'non_comp_acc',
header: {
label: '# of Non-Compliant Accounts',
formatters: [label => this.sortFormatter(label, 'non_compliant')],
transforms: [
property => ({
onClick: () => this.columnClick('non_compliant')
})
]
}
}, {
property: 'comp_acc',
header: {
label: '# of Compliant Accounts',
formatters: [label => this.sortFormatter(label, 'compliant')],
transforms: [
property => ({
onClick: () => this.columnClick('compliant')
})
]
}
}, {
property: 'percentage_compliant',
header: {
label: 'Percentage Compliant',
formatters: [label => this.sortFormatter(label, 'percentage_compliant')],
transforms: [
property => ({
onClick: () => this.columnClick('percentage_compliant')
})
]
},
cell: {
formatters: [this.percentageFormatter],
transforms: [
value => this.styleFormatter(value)
]
}
}];
render() {
return null;
}
}
const mapStateToProps = state => ({
sortCol: state.getSortColName.sort.sortColName,
sortColDir: state.getSortColName.sort.sortDir,
});
const mapDispatchToProps = dispatch => ({
sortColName: dataField => dispatch(sortColName(dataField)),
});
export default connect(mapStateToProps, mapDispatchToProps)(DashboardColumns);
Please advice. Also could someone help me out on the formatters stuff. I am getting what I want perfectly but is there a more cleaner code for this?
Set a transform like this
styleTransform = (cell) => {
if (cell >= 95) {
return { className: 'green-background' }
}
...
};
Issue at tracker: https://github.com/reactabular/reactabular/issues/341 .

Add key and value from other array of hash

I have two array of hashes .Both have similar values in them but i want to create new key in the hash that will have the some values of second array of hash.
First Array:
[
{ area_code => 93, name => 'Afghanistan', code => 'AF', slno => 4554 },
{ area_code => 1684, name => 'American Samoa', code => 'AS', slno => 4557 },
];
Second Array:
[
{ city => "Berat", country => "AS", id => 134368 },
{ city => "Durres", country => "AS", id => 138466 },
{ city => "Kabul", country => "AF", id => 142462 },
];
Now in the first hash i have key code whose value is similar to the second hash key country .So i want to add a new key in the second array of hash which will be country_name.And the country_name value will be the value of first array of hash name.
So how can we do this please help me in this
use strict;
use warnings;
my $a1 = [
{ area_code => 93, code => "AF", name => "Afghanistan", slno => 4554 },
{ area_code => 1684, code => "AS", name => "American Samoa", slno => 4557 },
];
my $a2 = [
{ city => "Berat", country => "AS", id => 134368 },
{ city => "Durres", country => "AS", id => 138466 },
{ city => "Kabul", country => "AF", id => 142462 },
];
my %h = map { $_->{code} => $_ } #$a1;
for my $v (#$a2) {
$v->{country_name} = $h{ $v->{country} }{name};
}
This is a similar idea to #mpapec's, but, I think, a little cleaner.
use strict;
use warnings;
my #array1 = (
{ area_code => 93, name => 'Afghanistan', code => 'AF', slno => 4554 },
{ area_code => 1684, name => 'American Samoa', code => 'AS', slno => 4557 },
);
my #array2 = (
{ country => 'AS', city => 'Berat', id => 134368 },
{ country => 'AS', city => 'Durres', id => 138466 },
{ country => 'AF', city => 'Kabul', id => 142462 },
);
{
my %names = map { $_->{code} => $_->{name} } #array1;
$_->{country_name} = $names{ $_->{country} } for #array2;
}
use Data::Dump;
dd \#array2;
output
[
{
country => 'AS',
city => 'Berat',
id => 134368,
country_name => 'American Samoa',
},
{
country => 'AS',
city => 'Durres',
id => 138466,
country_name => 'American Samoa',
},
{
country => 'AF',
city => 'Kabul',
id => 142462,
country_name => 'Afghanistan',
},
]

Access perl attribute in associative array

Is there an easier way to access the value of the 'type' attribute without looping through the whole object to find it?
[
{ type => "voipPassword", vals => ["data"] },
{ type => "sn", vals => ["data"] },
{ type => "voipExtension", vals => [data] },
{ type => "cn", vals => ["data"] },
{ type => "telephoneNumber", vals => [data] },
{ type => "objectClass", vals => ["data"] },
{ type => "phoneMAC", vals => ["data"] },
]
You can access type directly like this example:
#!/usr/bin/perl
use strict;
use warnings;
my $ref = [
{ type => "voipPassword", vals => ["data"] },
{ type => "sn", vals => ["data"] },
{ type => "voipExtension", vals => ["data"] },
{ type => "cn", vals => ["data"] },
{ type => "telephoneNumber", vals => ["data"] },
{ type => "objectClass", vals => ["data"] },
{ type => "phoneMAC", vals => ["data"] },
];
print $ref->[0]->{'type'} . "\n";
print $ref->[1]{'type'} . "\n";
Output:
voipPassword
sn
See perlreftut for more details.

creating hash from variables to be used in json encode/decode perl

i'm trying to create a test module to test json encoding. i am having issues creating variables that will output correctly with the json encode/decode. if i use just the $cat_1 in the #cats array, it will work fine. however, using both, it prints out "HASH(..." as you can see below.
use strict;
use JSON;
use Data::Dump qw( dump );
my $cat_1 = {'name' => 'cat1', 'age' => '6', 'weight' => '10 kilos', 'type' => 'siamese'};
my $cat_2 = {'name' => 'cat2', 'age' => '10', 'weight' => '13 kilos', 'type' => 'siamese'};
my #cats;
push(#cats, $cat_1);
push(#cats, $cat_2);
my $dog_1 = {'name' => 'dog1', 'age' => '7', 'weight' => '20 kilos', 'type' => 'siamese'};
my $dog_2 = {'name' => 'dog2', 'age' => '5', 'weight' => '15 kilos', 'type' => 'siamese'};
my #dogs;
push(#dogs, $dog_1);
push(#dogs, $dog_2);
my $pets = {'cats' => #cats, 'dogs' => #dogs};
my $a = { 'id' => '123', 'name' => 'Joe Smith', 'city' => "Chicago", 'pets' => $pets };
my $json = JSON->new->allow_nonref;
my $encoded = $json->encode($a);
my $decoded = $json->decode( $encoded );
print "\ndump cat_1\n";
dump $cat_1;
print "\ndump cats\n";
dump #cats;
print "\n\nOriginal\n";
dump $a;
print "\n\n";
print "Encoded\n";
print $encoded;
print "\n\n";
print "Decoded\n";
dump $decoded;
print "\n\n";
output
dump cat_1
{ age => 10, name => "cat1", type => "siamese", weight => "10 kilos" }
dump cats
(
{ age => 10, name => "cat1", type => "siamese", weight => "10 kilos" },
{ age => 10, name => "cat2", type => "siamese", weight => "3 kilos" },
)
Original
{
city => "Chicago",
id => 123,
name => "Joe Smith",
pets => {
"cats" => { age => 10, name => "cat1", type => "siamese", weight => "10 kilos" },
"HASH(0x176c3170)" => "dogs",
"HASH(0x1785f2d0)" => { age => 10, name => "dog2", type => "siamese", weight => "3 kilos" },
},
}
Encoded
{"city":"Chicago","pets":{"HASH(0x1785f2d0)":{"weight":"3 kilos","name":"dog2","type":"siamese","age":"10"},"cats":{"weight":"10 kilos","name":"cat1","type":"siamese","age":"10"},"HASH(0x176c3170)":"dogs"},"name":"Joe Smith","id":"123"}
Decoded
{
city => "Chicago",
id => 123,
name => "Joe Smith",
pets => {
"cats" => { age => 10, name => "cat1", type => "siamese", weight => "10 kilos" },
"HASH(0x176c3170)" => "dogs",
"HASH(0x1785f2d0)" => { age => 10, name => "dog2", type => "siamese", weight => "3 kilos" },
},
}
This line
my $pets = {'cats' => #cats, 'dogs' => #dogs};
is a red flag. It's valid Perl, but it's not doing what you would expect. Perl will flatten your lists in this construction, so if #cats contains ($cat_1,$cat_2) and #dogs containts ($dog_1,$dog_2), your expression is parsed as
my $pets = { 'cats', $cat_1, $cat_2, 'dogs', $dog_1, $dog_2 };
which is like
my $pets = { 'cats' => $cat_1, $cat_2 => 'dogs', $dog_1 => $dog_2 }
with the hash references $cat_2 and $dog_1 getting stringified before being used as hash keys.
Hash values must be scalar values, not arrays. But array references are OK. Try:
my $pets = {'cats' => \#cats, 'dogs' => \#dogs};
The problem is in the creation of $pets:
my $pets = {'cats' => #cats, 'dogs' => #dogs};
Is roughly equivalent to:
my $pets = {'cats', {name => 'cat1', ...}, {name => 'cat2', ...},
'dogs', {name => 'dog1', ...}, {name => 'dog2, ...} };
Which is the same as:
my $pets = {
'cats' => {name => 'cat1', ...},
{name => 'cat2'}, => 'dogs',
{name => 'dog1', ...}, => {name => 'dog2}
};
You want to use ArrayRefs:
my $pets = {'cats' => \#cats, 'dogs' => \#dogs};
Which is:
my $pets = {
'cats' => [
{name => 'cat1', ...},
{name => 'cat2', ...},
],
'dogs' => [
{name => 'dog1', ...},
{name => 'dog2', ...},
],
};
Which is also how you could declare the whole data structure at once.

Resources