perl asn1 module encode SEQUENCE OF SEQUENCE - perl

In the exmaple below, the asn1 definition has two tags schoolId and student. The tag student is SEQUENCE of SEQUENCE. I get the student info from a a file in JSON format such as:
{"school1": [{"name": "jason","id": 12345, "age": 14}, {"name": "karen","id": 12346, "age": 14},{"name": "mike","id": 12347, "age": 15}]}
{"school2": [{"name": "dave","id": 12645, "age": 16}, {"name": "angel","id": 12346, "age": 14},{"name": "susan","id": 12347, "age": 15}]}
So each school has a different number of students. My question is how to encode the student tag since it has unspecified number of students.
Thanks for your help!
use Convert::ASN1;
use Data::Dumper;
my %scope = qw(base 0 one 1 single 1 sub 2 subtree 2);
my %deref = qw(never 0 search 1 find 2 always 3);
my $search_pdu = Convert::ASN1->new;
$search_pdu->prepare(q(
SEQUENCE {
schoolId INTEGER,
student [0] SEQUENCE OF SEQUENCE {
name STRING,
id INTEGER,
age INTEGER
}
}
)) or die $search_pdu->error;
$buf = $search_pdu->encode(
schoolId => 1001,
student => [
{
name => "Jason Howard",
id => 310089,
age => 14
},
{
name => " Angel Disante",
id => 310456,
age => 15
}
]
);
$Data::Dumper::Indent = 1;
print Dumper( $search_pdu->decode($buf));
$h = unpack("H*",$buf);
print $h,"\n";
My question, For example, if school1 has 100 students, school2 has 300 students, ......., is there any way to use a for loop in the encode function to figure out the number of students programmatically?
$student_json = "{"school-1001": [{"name": "jason","id": 12345, "age": 14}, {"name": "karen","id": 12346, "age": 14},{"name": "mike","id": 12347, "age": 15}]}";
student => [
for my $hashref (#{$student_json}) {
{
name => $hashref->{'name'},
id => $hashref->{'id'},
age => $hashref->{'age'}
}
]
I tried many ways to use the for loop as shown above to encode programmatically, but it always failed.

My question, For example, if school1 has 100 students, school2 has 300 students, ......., is there any way to use a for loop in the encode function to figure out the number of students programmatically?
$student_json = "{"student": [{"name": "jason","id": 12345, "age": 14}, {"name": "karen","id": 12346, "age": 14},{"name": "mike","id": 12347, "age": 15}]}";
student => [
for my $hashref (#{$student_json}) {
{
name => $hashref->{'name'},
id => $hashref->{'id'},
age => $hashref->{'age'}
}
]

Given a JSON string with the school and student data, you can try:
use feature qw(say);
use strict;
use warnings;
use Convert::ASN1;
use Data::Dumper;
use JSON::XS;
my $json = <<'END';
{
"school1": [{"name": "jason","id": 12345, "age": 14}, {"name": "karen","id": 12346, "age": 14},{"name": "mike","id": 12347, "age": 15}],
"school2": [{"name": "dave","id": 12645, "age": 16}, {"name": "angel","id": 12346, "age": 14},{"name": "susan","id": 12347, "age": 15}]
}
END
my $hash = decode_json $json;
my $search_pdu = Convert::ASN1->new;
$search_pdu->prepare(q(
school SEQUENCE OF SEQUENCE {
schoolId INTEGER,
student SEQUENCE OF SEQUENCE {
name STRING,
id INTEGER,
age INTEGER
}
}
)) or die $search_pdu->error;
my #schools;
my $data = {school => \#schools};
my $school_id = 1001;
for my $school ( keys %$hash ) {
my #students;
my $item = { schoolId => $school_id, student => \#students };
for my $student (#{$hash->{$school}}) {
push #students, $student;
}
push #schools, $item;
$school_id++;
}
my $buf = $search_pdu->encode( $data );
$Data::Dumper::Indent = 1;
print Dumper( $search_pdu->decode($buf));
Output:
$VAR1 = {
'school' => [
{
'student' => [
{
'name' => 'jason',
'id' => 12345,
'age' => 14
},
{
'name' => 'karen',
'id' => 12346,
'age' => 14
},
{
'age' => 15,
'id' => 12347,
'name' => 'mike'
}
],
'schoolId' => 1001
},
{
'schoolId' => 1002,
'student' => [
{
'age' => 16,
'id' => 12645,
'name' => 'dave'
},
{
'name' => 'angel',
'age' => 14,
'id' => 12346
},
{
'name' => 'susan',
'age' => 15,
'id' => 12347
}
]
}
]
};

Related

Grouping Hash Tags with same hashTag name

I am finding a problem in group hashtags: Any Solution?
here is my query statement: any help.
def trending_tags(user)
#tags= HashTag.joins(:vibe_hash_tags).limit(10).where('hash_tags.created_at BETWEEN ? AND ?', 1.months.ago, Time.now).select("hash_tags.id, hash_tags.address as country, count(vibe_hash_tags.id) as vibes_hash_tags,COUNT(hash_tags.id)as hash_tag_count")
.group('COUNT(hash_tags.name as hash_tag_name)')
render :status => 200, :json => {:success => true, :result => { :trending_hash_tags => #tags}}
end
I would want to group it to this
{
"success": true,
"result": {
"trending_hash_tags": [
{
"id": 83,
"country": "TV",
"vibes_hash_tags": 2,
"hash_tag_name": "money",
"hash_tag_count": 2
},
{
"id": 84,
"country": "TV",
"vibes_hash_tags": 3,
"hash_tag_name": "grace",
"hash_tag_count": 3
}
]
}
}
I have been able to find a solution my question for grouping Hash Tags.
def trending_tags
#hash_tags= HashTag
.select('hash_tags.name AS hash_tag_name, COUNT(hash_tags
.id) AS hash_tag_count, hash_tags.address AS country, count(vibe_hash_tags.id) AS vibes_hash_tags')
.joins(:vibe_hash_tags)
.order('hash_tag_count DESC')
.group('hash_tags
.name, hash_tags.address').limit(10).where('hash_tags.created_at BETWEEN ? AND ?', 5.days.ago, Time.now)
render :status => 200, :json => {:success => true, :result => { :trending_hash_tags => #hash_tags}}
end

How to recreate perl's array of hashes in golang?

In perl I can push $hashref into #array and have this data for next foreach and possible encode_json (HTTP POST).
I can't figure out how to recreate the same login in golang?
$VAR1 = [
{
'address' => 'test.com',
'id' => 101,
'hostgroups' => [
zero
'one',
'or many'
],
'host_name' => 'test.com',
'alias' => 'test.com',
'template' => 'generic',
'file_id' => 'etc/config'
},
{
'address' => 'test2.com',
'id' => 102,
'hostgroups' => [
zero
'one',
'or many'
],
'host_name' => 'test2.com',
'alias' => 'test2.com',
'template' => 'generic',
'file_id' => 'etc/config'
},
(..)
var array = []map[string]interface{}{
{"address": "test.com", "hostgroups": []string{"zero", "one", "or many"}, "id": 101},
{"address": "test2.com", "hostgroups": []string{"zero", "one", "or many"}, "id": 102},
}
This is the answer.
type host map[string]interface{}
var hosts []host
h := host{
"id": id,
"file_id": "etc/config/hosts.cfg",
"host_name": host_name,
"alias": host_name,
"address": host_name,
"hostgroups": hg,
"template": "generic-host",
}
hosts = append(hosts, h)

Find average time between multiple datetime objects mongodb

I want to find the average time a client visit at particular location. My data structure is as follows:
{
"_id": ObjectId("5aea9f9a83b391f80e00a1b1"),
"Client": "ABC",
"Timestamp": "2018-05-03 10:47:42"
},
{
"_id": ObjectId("5aea9f9a83b391f80e00c1a1"),
"Client": "ABC",
"Timestamp": "2018-05-03 11:05:04"
} ,
{
"_id": ObjectId("5aea9f9a83b391f80e00a1e1"),
"Client": "ABC",
"Timestamp": "2018-05-03 13:05:04"
} ,
{
"_id": ObjectId("5aea9f9a83b391f80eaea1e1"),
"Client": "DEF",
"Timestamp": "2018-05-03 11:20:44"
}
I have just tried code so far in codeigniter
$optn = array(
array('$group' => array( '_id' => '$Client', 'date1' => array('$min' => '$Timestamp'), 'date2' => array('$max' => '$Timestamp'), 'avg_time' => array('$avg' => array('$subtract' => array('$date2', '$date1')))))
);
$repeatdata = $this->mongo_db->aggregate("logsdata", $optn);
echo '<pre>'; print_r($repeatdata);
It gives me result as:
Array
(
[waitedMS] => 0
[result] => Array
(
[0] => Array
(
[_id] => ABC
[date1] => 2018-05-03 10:47:42
[date2] => 2018-05-03 13:05:04
[avg_time] =>
)
[1] => Array
(
[_id] => DEF
[date1] => 2018-05-03 11:20:44
[date2] => 2018-05-03 11:20:44
[avg_time] =>
)
)
)

Convert a flat datastructure into a tree

I have an array of hashes. Each element in the array is a node in a hierarchical tree and has referential data for who the parent is. I will have thousands and hundreds of thousands of nodes in the tree... essentially an unknown set of nodes has to be converted to JSON (shown below) for use with http://bl.ocks.org/robschmuecker/7880033
UPDATE: position_id is a node in the heretical tree. placement_id is the parent's position_id (adjacency referential tree).
UPDATE: Here's the full AoH Data::Dumper result with Nested Set and Adjacency result from a modified version of DBIx::Tree::NestedSet (custom).
$VAR1 = [
{
'lft' => '673',
'id' => '109',
'date_created' => '2015-08-15',
'level' => '7',
'user_id' => '13',
'placement_id' => '11',
'position_id' => '13',
'status' => '1',
'structure_id' => '1',
'rght' => '684'
},
{
'placement_id' => '13',
'position_id' => '22',
'status' => '1',
'structure_id' => '1',
'rght' => '679',
'lft' => '674',
'date_created' => '2015-08-15',
'id' => '116',
'level' => '8',
'user_id' => '22'
},
{
'user_id' => '101',
'level' => '9',
'id' => '200',
'date_created' => '2015-08-15',
'lft' => '675',
'rght' => '676',
'structure_id' => '1',
'status' => '1',
'position_id' => '101',
'placement_id' => '22'
},
{
'date_created' => '2015-08-15',
'id' => '201',
'level' => '9',
'user_id' => '374',
'lft' => '677',
'structure_id' => '1',
'rght' => '678',
'placement_id' => '22',
'position_id' => '374',
'status' => '1'
},
{
'lft' => '680',
'user_id' => '95',
'level' => '8',
'id' => '117',
'date_created' => '2015-08-15',
'status' => '1',
'position_id' => '95',
'placement_id' => '13',
'rght' => '681',
'structure_id' => '1'
}
];
THIS IS THE GOAL, For this example I need to end up with:
{
"name": "13",
"children": [
{
"name": "22",
"children": [
{
"name": "101"
},
{
"name": "374"
}
]
},
{
"name": "95"
}
]
}
You can also see the format I am trying to arrive at here (minus size):
http://bl.ocks.org/robschmuecker/7880033#flare.json
My failed approach(es) included various attempts at looping through the array of hashes to create a recursive Hash of Hashes that can then be used with the JSON Perl module to create the actual JSON I need.
my $data = [
{ position_id => 123, placement_id => undef },
{ position_id => 456, placement_id => 123 },
{ position_id => 789, placement_id => 123 },
# ...
];
my $roots;
{
my %recs_by_name;
my %children_by_parent_name;
for my $row (#$data) {
my $name = $row->{position_id};
my $parent_name = $row->{placement_id};
my $rec = {
name => $name,
};
push #{ $children_by_parent_name{$parent_name // 'root'} }, $rec;
$recs_by_name{$name} = $rec;
}
$roots = delete($children_by_parent_name{root}) || [];
for my $name (keys(%children_by_parent_name)) {
my $children = $children_by_parent_name{$name};
if ( my $rec = $recs_by_name{$name} ) {
$rec->{children} = $children;
} else {
die("Parent $name doesn't exist.\n");
push #$roots, #$children;
}
}
}
print(Dumper($roots));
Tested.
You appear to have the depth of each node available to you (level). Simpler code could be used if your data was sorted by increasing depths.
While it was #ikegami who ultimately answered the question that led to the solution. I believe the following adaptation adds 4 important elements/clarifications I found helpful, and thought others reading this question and answer would also find useful.
1- Clear addition of all key,value pairs from the originating AoH to the resulting HOH. See while loop.
2- A Child node counter.
3- Inclusion and use of the encode_json function from JSON
4- The result is also an Array with a Hash as the first element. Newbies (like me) might find the explicit #{$roots}[0] passed to encode_json as helpful.
At first I had a similar adapted solution posted as an UPDATE within my question, but was admonished that it was bad etiquette and instructed to post an answer.
#ikegami's deserves the credit for the core of the solution.
sub get_jsonTree {
my ($array_of_hashes_ref) = #_;
my $roots;
my %recs_by_name;
my %children_by_parent_name;
my %count;
for my $row (#$array_of_hashes_ref) {
my $name = $row->{position_id};
my $parent_name = $row->{placement_id};
my $rec = {
name => $name,
};
## Added to loop through all key,value pairs and add them to $rec
while ( my ($key, $value) = each(%$row) ) {
$rec->{$key} = $value;
}
##Added To Count Child Nodes
$count{$parent_name} = 0 if (!$count{$parent_name});
$rec->{'child_count'} = $count{$parent_name};
$count{$parent_name}++;
push #{ $children_by_parent_name{$parent_name // 'root'} }, $rec;
$recs_by_name{$name} = $rec;
}
$roots = delete($children_by_parent_name{root}) || [];
for my $name (keys(%children_by_parent_name)) {
my $children = $children_by_parent_name{$name};
if ( my $rec = $recs_by_name{$name} ) {
$rec->{children} = $children;
} else {
$util{'test'} .= "Parent $name doesn't exist.\n<BR>";
push #$roots, #$children;
}
}
use JSON;
my $json_str = encode_json(#{$roots}[0]);
return $json_str;
}
my $array_of_hashes_ref = [
{ position_id => 123, placement_id => undef },
{ position_id => 456, placement_id => 123 },
{ position_id => 789, placement_id => 123 },
# ...
];
my $json_str = &get_jsonTree($array_of_hashes_ref);

Hash merge/concatenation

this is a dump of my hashes: %hash1
$VAR1 = {
abc => {
123 => [
'xx',
'yy',
'zy'
],
456 => [
'ab',
'cd',
'ef'
]
}
};
and the second one: %hash2
$VAR2 = {
def => {
659 => [
'wx',
'yg',
'kl'
],
456 => [
'as',
'sd',
'df'
]
},
abc => {
987 => [
'lk',
'dm',
'sd'
]
}
};
Now I want to merge these two hashes in a new hash, but if a key is duplicated (here 'abc'), the values should be appended, not replaced, so the keys should remain unique, and all the values should be retained as well. How can this be done in Perl?
The output should be as follows:
$VAR1 = {
def => {
659 => [
'wx',
'yg',
'kl'
],
456 => [
'as',
'sd',
'df'
]
},
abc => {
987 => [
'lk',
'dm',
'sd'
],
123 => [
'xx',
'yy',
'zy'
],
456 => [
'ab',
'cd',
'ef'
]
}
};
Use the CPAN modules Hash::Merge or Hash::Merge::Simple. The first is highly configurable and the second is very simple to use.
for my $x (keys(%h2)) {
for my $y (keys(%{ $h2{$x} })) {
push #{ $h1{$x}{$y} }, #{ $h2{$x}{$y} };
}
}
For the sample data provided, the following would perform the merging you describe:
my %merged = map {
$_ => {
%{$a{$_} // {}},
%{$b{$_} // {}}
}
} ( keys %a, keys %b );
Test:
use strict;
use warnings;
use Data::Dump 'dd';
my %a = (
abc => {
123 => [
'xx',
'yy',
'zy'
],
456 => [
'ab',
'cd',
'ef'
]
}
);
my %b = (
def => {
659 => [
'wx',
'yg',
'kl'
],
456 => [
'as',
'sd',
'df'
]
},
abc => {
987 => [
'lk',
'dm',
'sd'
]
}
);
my %merged = map {
$_ => {
%{$a{$_} // {}},
%{$b{$_} // {}}
}
} ( keys %a, keys %b );
dd \%merged;
# {
# abc => {
# 123 => ["xx", "yy", "zy"],
# 456 => ["ab", "cd", "ef"],
# 987 => ["lk", "dm", "sd"],
# },
# def => { 456 => ["as", "sd", "df"], 659 => ["wx", "yg", "kl"] },
# }
sub merge_hashes {
my ($h1, $h2) = #_;
foreach my $key (keys %$h2) {
if (!exists $h1->{$key} || ref($h1->{$key}) ne 'HASH' || ref($h2->{$key}) ne 'HASH') {
$h1->{$key} = $h2->{$key};
}
else {
merge_hashes($h1->{$key}, $h2->{$key});
}
}
}
merge_hashes(\%hash1, \%hash2);