Perl: Merging Hash elements - arrays

I have 2 hashes.
my %hash1 = (
'1.3.6.1.2.1.7.1.0' => 'switch_stuff1',
'1.3.6.1.2.1.6.3.0' => 'switch_stuff4',
'1.3.6.1.2.1.6.5.0' => 'switch_stuff5',
'1.3.6.1.2.1.7.4.0' => 'switch_stuff2',
'1.3.6.1.2.1.6.2.0' => 'switch_stuff3'
);
my %hash2 = (
'1.3.6.1.2.1.7.1.0' => 125858,
'1.3.6.1.2.1.6.3.0' => 120000,
'1.3.6.1.2.1.6.5.0' => 23766,
'1.3.6.1.2.1.7.4.0' => 115336,
'1.3.6.1.2.1.6.2.0' => 200
);
As you can see, the key values for both hashes are the same.
What I need to do is take the values from %hash1 and use them as keys for the %hash2.
Output:
$VAR1 = {
'switch_stuff1' => 125858,
'switch_stuff4' => 120000,
'switch_stuff5' => 23766,
'switch_stuff2' => 115336,
'switch_stuff3' => 200
};
Note: The number of keys/value pairs in both hashes will always be the same.
Alternatively, the only important thing to me about %hash1 are the values.
'switch_stuff1',
'switch_stuff4',
'switch_stuff5',
'switch_stuff2',
'switch_stuff3'
So if merging the hashes in the way I described is not possible, I can instead turn the %hash1 into an array that contains only the values.
Can anybody please help a Perl Newbie out or at least point me in the right direction? Any help would be greatly appreciated.
Thank you.

ETA:
Ah, I think I misunderstood you.. You wanted to join the two separate values into a hash. Easily done with map:
my %hash3 = map { $hash1{$_} => $hash2{$_} } keys %hash1;

my $hash1 = {
'1.3.6.1.2.1.7.1.0' => 'switch_stuff1',
'1.3.6.1.2.1.6.3.0' => 'switch_stuff4',
'1.3.6.1.2.1.6.5.0' => 'switch_stuff5',
'1.3.6.1.2.1.7.4.0' => 'switch_stuff2',
'1.3.6.1.2.1.6.2.0' => 'switch_stuff3'
};
my $hash2 = {
'1.3.6.1.2.1.7.1.0' => 125858,
'1.3.6.1.2.1.6.3.0' => 120000,
'1.3.6.1.2.1.6.5.0' => 23766,
'1.3.6.1.2.1.7.4.0' => 115336,
'1.3.6.1.2.1.6.2.0' => 200
};
my $hash3 = {}:
foreach $key (keys %$hash1) {
$hash3->{$hash1->{$key}} = $hash2->{$key};
}

Related

Iterating through a JSON array and returning a subset of elements

I'm new to JS and trying to figure out how to iterate through a json array and return only a subset of elements. Specifically I would like to know how to return only the 'first_name' and 'last_name' from the Mock data in the attached code snippet. It seems like it should be straightforward but I'm scratching my head.
let people = [{"id":1,"first_name":"Talbert","last_name":"Kohnert","email":"tkohnert0#wisc.edu","country":"Indonesia"},
{"id":2,"first_name":"Ruthie","last_name":"McKleod","email":"rmckleod1#gizmodo.com","country":"Sweden"},
{"id":3,"first_name":"Lenore","last_name":"Foister","email":"lfoister2#epa.gov","country":"Nicaragua"}]
people.forEach(person => {
for (let key in person) {
console.log(`${key} => ${person[key]}`);
}
Use the element names
people.forEach(person => {
console.log(JSON.stringify(person) + "\n");
console.log(person["first_name"], person["last_name"], "\n");
});
Produces this output:
{"id":1,"first_name":"Talbert","last_name":"Kohnert","email":"tkohnert0#wisc.edu","country":"Indonesia"}
Talbert Kohnert
{"id":2,"first_name":"Ruthie","last_name":"McKleod","email":"rmckleod1#gizmodo.com","country":"Sweden"}
Ruthie McKleod
{"id":3,"first_name":"Lenore","last_name":"Foister","email":"lfoister2#epa.gov","country":"Nicaragua"}
Lenore Foister
You can try Object destructuring assignment of ES6 to achieve the requirement.
Working Demo :
let people = [{"id":1,"first_name":"Talbert","last_name":"Kohnert","email":"tkohnert0#wisc.edu","country":"Indonesia"},
{"id":2,"first_name":"Ruthie","last_name":"McKleod","email":"rmckleod1#gizmodo.com","country":"Sweden"},
{"id":3,"first_name":"Lenore","last_name":"Foister","email":"lfoister2#epa.gov","country":"Nicaragua"}];
let res = people.map(({first_name, last_name}) => first_name + ' ' + last_name);
console.log(res);
There are numerous way of achieving this output. One of most frequently used method is using map() of es6.
let people = [{"id":1,"first_name":"Talbert","last_name":"Kohnert","email":"tkohnert0#wisc.edu","country":"Indonesia"},
{"id":2,"first_name":"Ruthie","last_name":"McKleod","email":"rmckleod1#gizmodo.com","country":"Sweden"},
{"id":3,"first_name":"Lenore","last_name":"Foister","email":"lfoister2#epa.gov","country":"Nicaragua"}]
//by map method
people.map((person,index)=>{
console.log(`${person.first_name} ${person.last_name}`)
})
// by forEach
people.forEach(person => {
console.log(`${person.first_name} ${person.last_name}`)
}
you can achieve this by using the map function.
map lets you iterate over each item in the array and return a new value for each iteration while returning a new array, so for your case:
let people = [
{"id":1,"first_name":"Talbert","last_name":"Kohnert","email":"tkohnert0#wisc.edu","country":"Indonesia"},
{"id":2,"first_name":"Ruthie","last_name":"McKleod","email":"rmckleod1#gizmodo.com","country":"Sweden"},
{"id":3,"first_name":"Lenore","last_name":"Foister","email":"lfoister2#epa.gov","country":"Nicaragua"}
]
const newArray = people.map((person) => {
return {
first_name: person.first_name,
last_name: person.last_name
}
})
console.log(newArray)
here you get a new array with just the properties you need.

React not re-rendering when state changed from hook

Edit: Thanks for the help everyone. I needed to change the reference of the array and fixed it by doing:
setData([...sorted])
I am currently rendering out a list of tasks. This is a snippet of my return function within a functional component:
const [ data, setData ] = useState( mockData )
<tbody>
{ data.map(d => <TaskItem key={d.claimable} task={d}/>) }
</tbody>
When I click on a certain button on the page, the dataset gets sorted and I call setData(sortedData)
For some reason, the table isnt being re-rendered with the sorted data. Is there something I did wrong here?
This is the sort function:
function filterByContactAmount():void {
let sorted = data.sort((a:any, b:any) => {
let aTimesContacted:number = a.data.person.contact.list.reduce((acc:number, val:any):number => acc + val.history.length, 0)
let bTimesContacted:number = b.data.person.contact.list.reduce((acc:number, val:any):number => acc + val.history.length, 0)
if ( aTimesContacted > bTimesContacted ) {
return 1
}
if ( bTimesContacted > aTimesContacted ) {
return -1
}
return 0;
})
console.log(sorted)
setData(sorted)
}
Its because you are using the same ref of the array, you need set the new data with
setData(old => "sorted data");
to change the reference of the state and it updates
function filterByContactAmount():void {
let sorted = data.sort((a:any, b:any) => {
let aTimesContacted:number = a.data.person.contact.list.reduce((acc:number, val:any):number => acc + val.history.length, 0)
let bTimesContacted:number = b.data.person.contact.list.reduce((acc:number, val:any):number => acc + val.history.length, 0)
if ( aTimesContacted > bTimesContacted ) {
return 1
}
if ( bTimesContacted > aTimesContacted ) {
return -1
}
return 0;
})
console.log(sorted)
setData(old => [...sorted]) // Sorted is the new state sorted
}
You are mutating sate, the other answer is probably not the best because you are still mutating state and then setting state with a copy of the already mutated value.
The sort function can also be optimized. Maybe try the following:
function filterByContactAmount() {
let sorted = data
.map(d => ({//map shallow copies the array
...d,//shallow copies the item
sortedNum: d.data.person.contact.list.reduce(//do this once for every item, not for every time sort callback is called
(acc, val) => acc + val.history.length,
0
),
}))
.sort((a, b) => a.sortedNum - b.sortedNum);
console.log(sorted);
setData(sorted);
}
I think issue is located under d.claimable, I suppose it is boolean variable type. You must know that every key prop must be unique. Check if you have for example.id property, if not add it.
Uniqueness of key prop is very important during reconciliation process.
Unique identifier with a group of children to help React figure out which items have changed, have been added or removed from the list. It’s related to the “lists and keys” functionality of React described here.
Very nice article about reconciliation.
<tbody>
{ data.map(d => <TaskItem key={d.claimable} task={d}/>) }
</tbody>

Looping within const in ReactJS

This is really minimal... but I haven't been able to figure this out.
const compose_url = (id, key) =>
`${id}/image/_/${key}`;
const get_images = compose_url(
this.props.dataset_id, // pass in prefix (2018_1_25)
get_image_arrays // This returns an array with two arrays e.g. [["img1.png"], ["img2.png"]]
);
I want this to return "2018_1-25/img1.png" and "2018_1-25/img2.png", but I'm only getting that for the first array, ("2018_1-25/img1.png") not for the second one. How could I loop through this to add the prefix to both images?
Please help... I haven't found documentation or examples on how to do this.
You need to update compose_url() function here, and make sure you always pass array as second of the vairable.
const compose_url = (date, imageArray) =>
imageArray.map((eachImage) => `${id}/image/_/${eachImage}`);
hope this helps.
const get_images = [];
const { dataset_id: id } = this.props;
get_images_array.forEach(arr => {
arr.forEach(path => {
get_images.push(
compose_url(
id,
path
)
);
}
});
EDIT:
I took a different approach to other answers and instead of modifying the compose_url method, I worked off of the the given data. This approach iterates over the top level array (get_images_array) and then iterates over each of the arrays in get_images_array. For each path in the inner arrays, the result of compose_url is pushed onto the get_images result array.
try this.
const compose_url = (id, arr) => {
return arr.map((ar) => (
`${id}/image/_/${ar}`
));
};
This function will return [ "2018_1_25/image/_/img1.png", "2018_1_25/image/_/img2.png" ]
You can simply map over the array like
const compose_url = (id, arr) => {
return [].concat(arr.map(data => [].concat(data.map(key) => `${id}/${key}`)));
}
const get_images = compose_url(
this.props.dataset_id, // pass in prefix (2018_1_25)
get_image_arrays // This returns an array with two arrays e.g. [["img1.png"], ["img2.png"]]
);

Select from table where both columns have same value

I have the code that selects all articles. What I am doing is, I think, wrong. I am selecting all values and then I am executing them.
Article::all()->each(function($article) {
if ($article->created_at == $article->published_at && $article>published) {
$article->update(['published_at' => null]);
}
});
What I need to do is select only those articles that have the mentioned created_at and updated_at the same.
How could I do that on the database level?
I need sth like that:
Article::where('created_at', '=', 'published_at')->where('published')->get()->each(function($article) {
$article->update(['published_at' => null]);
}
});
This code sure does not work, its just for imagine.
edit your code
Article::all()->each(function($article) {
if ($article->created_at == $article->published_at && $article->published) {
$article->update(['published_at' => null]);
}
});
You only need to search on the two columns for the one value:
Article::where(['created_at' => $date, 'updated_at' => $date ])->get();
Edit:
Use whereRaw for this
Article::whereRaw('created_at = updated_at')->get();

telerik mvc grid with one master and two detail grid

I have one master but two detail grids (detail grids on the same level). But telerik mvc grid is not able to render the same.
So I just tried master grid with detail to be simple template as below.
#(Html.Telerik().Grid<VIDEO_MASTER>()
.Name("Videos")
.Columns(col =>
{
col.Bound(t => t.VIDEO_ID).Hidden(true);
col.Bound(t => t.VIDEO_NAME).Width(200).Title("Video Name");
col.Bound(t => t.VIDEO_SHORT_NAME).Width(150).Title("Video Short Name");
col.Bound(t => t.VIDEO_ALTERNATE_NAME).Width(200).Title("Video Alternate Name");
col.Bound(t => t.PART_NUMBER).Width(60).Title("Part No");
col.Bound(t => t.DURATION).Width(80).Title("Duration");
col.Command(cmd =>
{
cmd.Edit().ButtonType(GridButtonType.Image);
cmd.Delete().ButtonType(GridButtonType.Image);
}).Width(100).Title("Cmd");
})
.ToolBar(commands =>
{
commands.Insert().ButtonType(GridButtonType.ImageAndText).HtmlAttributes(new { id = "masterAddBtn" });
commands.Custom().HtmlAttributes(new { id = "export" }).Text("Export").Action("Video_Export", "Video");
commands.Custom().HtmlAttributes(new { id = "exportdet" }).Text("Export Detail").Action("Video_ExportDet", "Video");
})
.DataKeys(keys => keys.Add(tkey => tkey.VIDEO_ID).RouteKey("id"))
.DataBinding(dataBinding => dataBinding.Ajax()
.Select("Select_Videos", "Video")
.Insert("Insert_Videos", "Video")
.Update("Update_Videos", "Video")
.Delete("Delete_Videos", "Video")
)
.ClientEvents(events => events.OnDataBound("onDataBound").OnEdit("onEdit"))
.Pageable(pagezie => pagezie.PageSize(5))
.Filterable()
.Scrollable(s => s.Height(440))
.DetailView(details => { details.ClientTemplate("<p>Hello</p>");
details.ClientTemplate("<p>Hi</p>");
})
)
What is going wrong? MVC telrik grid does not support two details row?
Caliing the ClientTemplate second time overwrites the first one. Just append the elements into single string.
.DetailView(details => { details.ClientTemplate("<p>Hello</p><p>Hi</p>");

Resources