I have two file generated from IntexCalc and Intex API, and I want to compare their content. I do not want to compare line by line. Below example will give more detail about it.
File 1
LOSS_UNITS[\"GRPY\"]==CDR
LOSS_USERCURVE_TYPE[\"GRPY\"]==PCT_MULTIPLY
LOSS_USERCURVE_INDEX_OFFSET[\"GRPY\"]==BY_LOAN_AGE
LOSS_RATE[\"GRPY\"]==100
LOSS_NONPERF_ADV_PCT_P[\"GRPY\"]==0
LOSS_NONPERF_ADV_PCT_I[\"GRPY\"]==0
SEVERITY_USERCURVE_TYPE[\"GRPY\"]==NONE
File 2
LOSS_USERCURVE_TYPE[\"GRPY\"]=PCT_MULTIPLY
LOSS_NONPERF_ADV_PCT_P[\"GRPY\"]=0
LOSS_UNITS[\"GRPY\"]=CDR
LOSS_NONPERF_ADV_PCT_I[\"GRPY\"]=0
SEVERITY_USERCURVE_TYPE[\"GRPY\"]=NONE
LOSS_SEVERITY[\"GRPY\"]=31.73
LOSS_USERCURVE_INDEX_OFFSET[\"GRPY\"]=BY_DEAL_AGE
I want to compare the LOSS_UNITS[\"GRPY\"] flag value from both files. In both files their value after =/== is the same regardless of their position in file, so this flag value is equal.
The flag value of LOSS_USERCURVE_INDEX_OFFSET[\"GRPY\"] in File 1 is BY_LOAN_AGE and in File 2 is BY_DEAL_AGE, so this flag value is different.
The flag LOSS_RATE[\"GRPY\"] is present only in File 1 so this is a difference
The flag LOSS_SEVERITY[\"GRPY\"] is present only in File 2 so this is also a difference.
What is the best way or tool to compare this kind of file structure?
I suggest you make use of the Data::Diff module
It returns a reference to a hash containing a summary of the differences between the parameters. The keys are
same — elements that are the same in both cases
diff — elements that have a different value for a given key
uniq_a and uniq_b — elements that appear in only one structure or the other
use strict;
use warnings 'all';
use autodie;
use Data::Dump;
use Data::Diff 'Diff';
my %f1 = do {
open my $fh, '<', 'file1.txt';
map { s/\s+\z//; split /=+/, $_, 2 } <$fh>;
};
my %f2 = do {
open my $fh, '<', 'file2.txt';
map { s/\s+\z//; split /=+/, $_, 2 } <$fh>;
};
my $diff = Diff(\(%f1, %f2));
dd $diff;
output
{
diff => {
"LOSS_USERCURVE_INDEX_OFFSET[\\\"GRPY\\\"]" => { diff_a => "BY_LOAN_AGE", diff_b => "BY_DEAL_AGE", type => "" },
},
same => {
"LOSS_NONPERF_ADV_PCT_I[\\\"GRPY\\\"]" => { same => 0, type => "" },
"LOSS_NONPERF_ADV_PCT_P[\\\"GRPY\\\"]" => { same => 0, type => "" },
"LOSS_UNITS[\\\"GRPY\\\"]" => { same => "CDR", type => "" },
"LOSS_USERCURVE_TYPE[\\\"GRPY\\\"]" => { same => "PCT_MULTIPLY", type => "" },
"SEVERITY_USERCURVE_TYPE[\\\"GRPY\\\"]" => { same => "NONE", type => "" },
},
type => "HASH",
uniq_a => { "LOSS_RATE[\\\"GRPY\\\"]" => 100 },
uniq_b => { "LOSS_SEVERITY[\\\"GRPY\\\"]" => 31.73 },
}
An uninspired solution: put keys and values into two hashes and compare them.
sub f2h {
my( $hr, $path ) = #_;
open FILE, $path or die "$path: couldn't open: $!";
while( my $line = <FILE> ){
$line =~ s/\s+$//; # there are trailing spaces in your data
my( $key, $val ) = split( /==?/, $line );
$hr->{$key} = $val;
}
close FILE;
}
my %h1;
my %h2;
f2h( \%h1, "file1.dat" );
f2h( \%h2, "file2.dat" );
while( my( $k, $v ) = each %h1 ){
if( exists( $h2{$k} ) ){
print "different $k\n" if $h2{$k} ne $v;
} else {
print "$k missing in 2\n";
}
}
while( my( $k, $v ) = each %h2 ){
print "$k missing in 1\n" unless exists $h1{$k};
}
Related
I am trying to export data to excel using Fast excel. This is easy for straight forward export. However, I have data as follows:
Illuminate\Support\Collection Object
(
[items:protected] => Array
(
[0] => stdClass Object
(
[id] => 1
[name] => name1
[multiple_units] => ["80","103","126","7","10","13"]
)
[1] => stdClass Object
(
[id] => 2
[name] => name2
[multiple_units] => ["30","23","26","7","25","33"]
)
)
)
Where multiple_units is a text column with json_decode. So, now when I try to export data with following code:
public function exportTest()
{
$reviews = DB::table('test_db')->get();
$file_name = 'Review - '.date('Y_m_d').'.xlsx';
return (new FastExcel($reviews))->download($file_name,function($review){
$unit_lists = '';
if($review->multiple_units != NULL){
$unit_ids = json_decode($review->multiple_units, true);
foreach($unit_ids as $uk => $uv){
return [
'Name' => $review->name,
'Units' => $uv
];
}
}
});
}
It export to excel file like as:
Name Units
name1 80
name2 30
However, I want to export with each unit being in a single row. For instance,
Name Units
name1 80
name1 103
name1 126
name1 7
name1 10
name1 13
...
...
...
...
As far as I can see, Fast Excel does not allow changing the number of rows in the callback function.
The solution is to manipulate the data before passing it to Fast Excel:
public function exportTest()
{
$reviews = DB::table('test_db')->get()->flatMap(function ($review) {
$items = [];
if ($review->multiple_units != NULL) {
$unit_ids = json_decode($review->multiple_units, true);
foreach ($unit_ids as $uk => $uv) {
$items[] = [
'Name' => $review->name,
'Units' => $uv
];
}
}
return $items;
});
$file_name = 'Review - '.date('Y_m_d').'.xlsx';
return (new FastExcel($reviews))->download($file_name);
}
This will map over each review return an array containing name and units for each unit. Then the array is flattened and passed to Fast Excel.
Note: This will ignore any reviews where review->multiple_units == NULL (which includes an empty string)
public function exportTest() {
$reviews = DB::table('test_db')->orderBy('name')->get();
$file_name = 'Review - '.date('Y_m_d').'.xlsx';
return (new FastExcel($reviews))->download($file_name,function($reviews) {
foreach ($reviews as $review) {
# code...
if(!empty($review->multiple_units)) {
$unit_ids = json_decode($review->multiple_units, true);
foreach($unit_ids as $uk => $uv){
return [
'Name' => $review->name,
'Units' => $uv
];
}
}
}
});
}
I wrote the simple macro:
macro_rules! my_macro {
{
f($x:expr, $y:expr, $z:expr);
$($c:expr => {
$($m:expr => {
$($s:expr => $b:expr),+
}),+
}),+
} => {{
match ($x, $y, $z) {
$(
($c, $m, $s => $b),
)+
}
}};
}
fn main(){
let c = 0;
let m = 0;
let s = 0;
my_macro! {
f (c, m, s);
cc => {
mm => {
ss => b
}
}
}
}
and it gets compiler errors:
error: variable 'm' is still repeating at this depth
--> project/src/mod.rs
|
39 | ($c, $m, $s => $b),
| ^^^^^^^
I do not completely understand why it did happen.
Why and how to repair that?
In your rule for your macro,
f($x:expr, $y:expr, $z:expr);
$($c:expr => {
$($m:expr => {
$($s:expr => $b:expr),+
}),+
}),+
$x, $y and $z bind a single expr. However, a whole list of $cs are bound. Moreover, associated to each $c is a whole list of $m because $m is still inside the $(...).+ block associated with $c. For each of those $ms, a whole list of $ss is bound.
Now in your output,
{{
match ($x, $y, $z) {
$(
($c, $m, $s => $b),
)+
}
}};
you only unpack one layer of lists with $(...)+. After one layer, $m is still a list of expressions ("repeating"), so it can't be used directly. Remember that $m is really a list of lists (since there's a list of $m for each $c) and $s is really a list of lists of lists.
You're either going to need to restructure the rule so that there's only one $m and one $s for each $c (all within one $(...),+) or you're going to need to restructure the output so that $m and $s get unpacked an appropriate number of times.
After trying the first approach (a single $(...),+ in the input rule), I'd suggest making $c, $m and $s patterns rather than expressions (as in $c: pat instead of $c: expr). This allows them to be used in the left side of a match branch.
macro_rules! my_macro {
{
f($x:expr, $y:expr, $z:expr);
$($c:pat => {
$m:pat => {
$s:pat => $b:expr
}
}),+
} => {
match ($x, $y, $z) {
$(
($c, $m, $s) => $b,
)+
}
};
}
The real solution depends a lot on what exactly you're trying to accomplish.
i am trying to append new rows in an excel file, only the last data is present , since it overwrites any previous data written , in this code i have a for loop that loops again to write the same data in a second row but , instead it rewrites the existing data
use strict;
use warnings;
use Excel::Writer::XLSX;
my $workbook = Excel::Writer::XLSX->new( 'ke.xlsx' );#create the excel
my $worksheet = $workbook->add_worksheet();
my $server= "se";
my $domain = "de";
my $backup = "b";
# Some sample data for the table.
my $data = [[ $server, $domain ,$backup],
];
$worksheet->set_column( 'A:G', 20 );
for(my $i = 0 ;$i<2;$i++){
$worksheet->add_table( # Add a table to the worksheet.
'A1:G8',
{
data => $data,
total_row => 1,
columns => [
{
header => 'server name',
},
{
header => 'Domain Name',
},
{
header => 'Back Up address',
}
]
}
);
}
Your code writes the table at A1:G8 each time. You need to change that if you want the tables in different places.
Seems to work for me using sample data:
use strict;
use warnings;
use Excel::Writer::XLSX;
my $workbook = Excel::Writer::XLSX->new('ke.xlsx' );#create the excel
my $worksheet = $workbook->add_worksheet();
#my $server= "se";
#my $domain = "de";
#my $backup = "b";
# Some sample data for the table.
#my $data = [[ $server, $domain ,$backup],
# ];
my $data = [ ["se", "de","b"],
["ll", "pp","t"],
["yu", "ar","e"],
["gt", "po","w"],
["br", "tp","g"] ];
$worksheet->set_column( 'A:G', 20 );
for(my $i = 0 ;$i<2;$i++){
$worksheet->add_table( # Add a table to the worksheet.
'A1:G8',
{
data => $data,
total_row => 1,
columns => [
{
header => 'server name',
},
{
header => 'Domain Name',
},
{
header => 'Back Up address',
}
]
}
);
}
I have worked on this module, however we did not used add_table instead we used $worksheet->write_row.
I think you should try writing your data using write_row
https://metacpan.org/pod/Excel::Writer::XLSX
If you don't want to use write_row, then for more examples on add_table please visit : https://metacpan.org/pod/Excel::Writer::XLSX#TABLES-IN-EXCEL
Hope that helps :)
ArangoDB provides documents and edges as a low level way to produce graphs.
Let's say we have set up a graph with some vertices and edges.
The graph represents the relationship between the vertices.
v2 is a child of v1
v3 is a child of v2
v4 is a child of v3
v5 is a child of v1
v6 is a child of v5
We want to be able to query:
The path from v4 to v1
All descendants of v1
The children of v1
All ancestors of v4
The parents of v4
How to do that in PHP?
The way to do this is by querying ArangoDB with its AQL (ArangoDB Query language).
There are a few commands for working with graphs in AQL.
With PHP, we have to create a statement with the query and execute that.
The attached code uses the TRAVERSAL function in order to provide the results to the queries mentioned in the question.
This script sets up a document and an edge collection, fills it with vertices and connecting edges, and finally does the querying in order to provide the results.
It can be executed as is and will print out all the results.
<?php
namespace triagens\ArangoDb;
// use this and change it to the path to autoload.php of the arangodb-php client if you're using the client standalone...
// require __DIR__ . '/../vendor/triagens/ArangoDb/autoload.php';
// ...or use this and change it to the path to autoload.php in the vendor directory if you're using Composer/Packagist
require __DIR__ . '/../vendor/autoload.php';
// This function will provide us with our pre-configured connection options.
function getConnectionOptions()
{
$traceFunc = function ($type, $data) {
print "TRACE FOR " . $type . PHP_EOL;
};
return array(
ConnectionOptions::OPTION_ENDPOINT => 'tcp://localhost:8529/',
// endpoint to connect to
ConnectionOptions::OPTION_CONNECTION => 'Close',
// can use either 'Close' (one-time connections) or 'Keep-Alive' (re-used connections)
ConnectionOptions::OPTION_AUTH_TYPE => 'Basic',
// use basic authorization
/*
ConnectionOptions::OPTION_AUTH_USER => '', // user for basic authorization
ConnectionOptions::OPTION_AUTH_PASSWD => '', // password for basic authorization
ConnectionOptions::OPTION_PORT => 8529, // port to connect to (deprecated, should use endpoint instead)
ConnectionOptions::OPTION_HOST => "localhost", // host to connect to (deprecated, should use endpoint instead)
*/
ConnectionOptions::OPTION_TIMEOUT => 5,
// timeout in seconds
//ConnectionOptions::OPTION_TRACE => $traceFunc, // tracer function, can be used for debugging
ConnectionOptions::OPTION_CREATE => false,
// do not create unknown collections automatically
ConnectionOptions::OPTION_UPDATE_POLICY => UpdatePolicy::LAST,
// last update wins
);
}
// This function tries to create vertices and edges for the example
function setupVerticesAndEdges($connection, $vertexCollection, $edgeCollection)
{
echo "We are creating 6 vertices...<br> ";
//create example documents for the vertices
$nameV1 = 'v1';
$documentV1 = Document::createFromArray(
array('name' => $nameV1, '_key' => $nameV1)
);
$nameV2 = 'v2';
$documentV2 = Document::createFromArray(
array('name' => $nameV2, '_key' => $nameV2)
);
$nameV3 = 'v3';
$documentV3 = Document::createFromArray(
array('name' => $nameV3, '_key' => $nameV3)
);
$nameV4 = 'v4';
$documentV4 = Document::createFromArray(
array('name' => $nameV4, '_key' => $nameV4)
);
$nameV5 = 'v5';
$documentV5 = Document::createFromArray(
array('name' => $nameV5, '_key' => $nameV5)
);
$nameV6 = 'v6';
$documentV6 = Document::createFromArray(
array('name' => $nameV6, '_key' => $nameV6)
);
echo "We are creating 5 edges...<br> ";
//create example documents for the edges
$nameE1 = 'e1';
$documentE1 = Edge::createFromArray(
array('name' => $nameE1, 'label' => 'child_of')
);
$nameE2 = 'e2';
$documentE2 = Edge::createFromArray(
array('name' => $nameE2, 'label' => 'child_of')
);
$nameE3 = 'e3';
$documentE3 = Edge::createFromArray(
array('name' => $nameE3, 'label' => 'child_of')
);
$nameE4 = 'e4';
$documentE4 = Edge::createFromArray(
array('name' => $nameE4, 'label' => 'child_of')
);
$nameE5 = 'e5';
$documentE5 = Edge::createFromArray(
array('name' => $nameE5, 'label' => 'child_of')
);
// Get instances of the vertice- and edgehandlers
$documentHandler = new DocumentHandler($connection);
$edgeHandler = new EdgeHandler($connection);
// Save the vertices
try {
// query the given $collectionId by example using the previously declared $exampleDocument array
$result['v'][] = $documentHandler->save($vertexCollection, $documentV1);
$result['v'][] = $documentHandler->save($vertexCollection, $documentV2);
$result['v'][] = $documentHandler->save($vertexCollection, $documentV3);
$result['v'][] = $documentHandler->save($vertexCollection, $documentV4);
$result['v'][] = $documentHandler->save($vertexCollection, $documentV5);
$result['v'][] = $documentHandler->save($vertexCollection, $documentV6);
} catch (Exception $e) {
// any other error
echo ('An error occured. Exception: ' . $e);
}
// Save the edges
try {
echo "$nameV2 is a child of $nameV1<br> ";
$result['e'][] = $edgeHandler->saveEdge(
$edgeCollection,
$vertexCollection . '/' . $nameV2,
$vertexCollection . '/' . $nameV1,
$documentE1,
$options = array()
);
echo "$nameV3 is a child of $nameV2<br> ";
$result['e'][] = $edgeHandler->saveEdge(
$edgeCollection,
$vertexCollection . '/' . $nameV3,
$vertexCollection . '/' . $nameV2,
$documentE2,
$options = array()
);
echo "$nameV4 is a child of $nameV3<br> ";
$result['e'][] = $edgeHandler->saveEdge(
$edgeCollection,
$vertexCollection . '/' . $nameV4,
$vertexCollection . '/' . $nameV3,
$documentE3,
$options = array()
);
echo "$nameV5 is a child of $nameV1<br> ";
$result['e'][] = $edgeHandler->saveEdge(
$edgeCollection,
$vertexCollection . '/' . $nameV5,
$vertexCollection . '/' . $nameV1,
$documentE4,
$options = array()
);
echo "$nameV6 is a child of $nameV5<br> ";
$result['e'][] = $edgeHandler->saveEdge(
$edgeCollection,
$vertexCollection . '/' . $nameV6,
$vertexCollection . '/' . $nameV5,
$documentE5,
$options = array()
);
echo "<font style='font-family: monospace;'>";
echo "$nameV1<br> ";
echo "+ $nameV2<br> ";
echo "| + $nameV3<br> ";
echo "| | + $nameV4<br> ";
echo "+ $nameV5<br> ";
echo "+ $nameV5<br> ";
echo "| + $nameV6<br> ";
echo "</font>";
// return the result;
return $result;
} catch (Exception $e) {
// any other error
echo ('An error occured. Exception: ' . $e);
}
}
// helper function that takes the connection and the query to execute.
function doAQLQuery($connection, $query)
{
// query through AQL
$statement = new \triagens\ArangoDb\Statement($connection, array(
"query" => '',
"count" => true,
"batchSize" => 1000,
"_sanitize" => true,
));
$statement->setQuery($query);
$cursor = $statement->execute();
$result = $cursor->getAll();
return $result;
}
// AQL query example functions
// Function that gets all paths from vertex v4 to v1
function getPathFromV4ToV1($connection)
{
$query = 'FOR p IN PATHS(vertices_20130301_01, edges_20130301_01, "outbound")
FILTER p.source._id == "vertices_20130301_01/v4" && p.destination._id == "vertices_20130301_01/v1"
RETURN p';
$result = doAQLQuery($connection, $query);
return $result;
}
// Function that gets the paths to all descendants of v1
function getPathToAllDescendantsOfV1($connection)
{
$query = 'FOR p IN TRAVERSAL(vertices_20130301_01, edges_20130301_01, "vertices_20130301_01/v1", "inbound", {
strategy: "depthfirst",
minDepth:1,
paths: true,
followEdges: [ { label: "child_of" } ]
})
RETURN p
';
$result = doAQLQuery($connection, $query);
return $result;
}
// Function that gets the paths to all children of v1
function getPathToChildrenOfV1($connection)
{
$query = 'FOR p IN TRAVERSAL(vertices_20130301_01, edges_20130301_01, "vertices_20130301_01/v1", "inbound", {
strategy: "depthfirst",
maxDepth: 1,
minDepth:1,
paths: true,
followEdges: [ { label: "child_of" } ]
})
RETURN p
';
$result = doAQLQuery($connection, $query);
return $result;
}
// Function that gets the paths to all parents of v4
function getPathToParentsOfV4($connection)
{
$query = 'FOR p IN TRAVERSAL(vertices_20130301_01, edges_20130301_01, "vertices_20130301_01/v4", "outbound", {
strategy: "depthfirst",
maxDepth: 1,
minDepth:1,
paths: true,
followEdges: [ { label: "child_of" } ]
})
RETURN p
';
$result = doAQLQuery($connection, $query);
return $result;
}
// Function that gets the paths to all ancestor of v4
function getPathToAllAncestorsOfV4($connection)
{
$query = 'FOR p IN TRAVERSAL(vertices_20130301_01, edges_20130301_01, "vertices_20130301_01/v4", "outbound", {
strategy: "depthfirst",
minDepth:1,
paths: true,
followEdges: [ { label: "child_of" } ]
})
RETURN p
';
$result = doAQLQuery($connection, $query);
return $result;
}
// Function that drops collections given
function dropCollections($connection, $collections)
{
// register a collection handler to work with the 'users' collection
$collectionHandler = new CollectionHandler($connection);
echo "dropping collections...";
try {
foreach ($collections as $collection) {
$collectionHandler->drop($collection);
}
echo "dropped.<br>";
} catch (Exception $e) {
die ('Could not drop collection. Exception: ' . $e . '<br>');
}
}
// *********************************************************************************************************************
// Start example code
// register the connection to ArangoDB
$connection = new Connection(getConnectionOptions());
// register a collection handler to work with the 'users' collection
$collectionHandler = new CollectionHandler($connection);
// assign the collection names...
$vertexCollection = 'vertices_20130301_01';
$edgeCollection = 'edges_20130301_01';
// finally drop the collections...
// remark this line if you want to drop the collections by hand.
dropCollections($connection, array($vertexCollection, $edgeCollection));
// create the vertices and edges collections...
// remark those lines if you want to create the collection by hand.
echo "creating the '$vertexCollection' vertex collection...";
try {
$collection = new Collection();
$collection->setName($vertexCollection);
$collectionHandler->create($collection);
echo "created.<br>";
} catch (Exception $e) {
echo ('Could not create collection. Exception: ' . $e . '<br>');
}
echo "creating the '$edgeCollection' edge collection...";
try {
$collection = new Collection();
$collection->setName($edgeCollection);
$collection->setType(3);
$collectionHandler->create($collection);
echo "created.<br>";
} catch (Exception $e) {
echo ('Could not create collection. Exception: ' . $e . '<br>');
}
// setup our vertices and edges....
echo "trying to setup our vertices and edges... <br>";
$result = setupVerticesAndEdges($connection, $vertexCollection, $edgeCollection);
// AQL Examples
// get the path from vertex v4 to v1
$result = getPathFromV4ToV1($connection);
echo "<br>*****************************************<br>";
echo "get all paths from vertex v4 to v1<br>";
echo "<br>*****************************************<br>";
var_dump($result);
// get the paths to all descendants of v1
$result = getPathToAllDescendantsOfV1($connection);
echo "<br>*****************************************<br>";
echo "get the paths to all descendants of v1<br>";
echo "<br>*****************************************<br>";
var_dump($result);
//get the paths to all children of v1
$result = getPathToChildrenOfV1($connection);
echo "<br>*****************************************<br>";
echo "get the paths to all children of v1<br>";
echo "<br>*****************************************<br>";
var_dump($result);
// get the paths to all ancestors of v4
$result = getPathToAllAncestorsOfV4($connection);
echo "<br>*****************************************<br>";
echo "get the paths to all ancestors of v4<br>";
echo "<br>*****************************************<br>";
var_dump($result);
//get all paths to all parents of v4
$result = getPathToParentsOfV4($connection);
echo "<br>*****************************************<br>";
echo "get all paths to all parents of v4<br>";
echo "<br>*****************************************<br>";
var_dump($result);
I've a very large hash-of-hash with upwards of 50,000 entries. I want to process this multi-threaded due to time constraints.
Is it possible for each call to dequeue() to return the next item from the hash, and not the complete hash? In the example below I want dequeue() to return just:
flintstones => {
old_address => "0x1231234a",
new_address => "0x1234234d",
source => "sym"
},
I can then process that in my thread whilst another thread dequeues another item from the hash until all items are processed. My code example below.
If I need to change the storage format (HoH) that's not a problem. Perhaps an array of hashes would work? Any help/pointer appreciated.
use strict;
use warnings;
use threads;
use Thread::Queue;
use Data::Dumper;
my %hoh = (
flintstones => {
old_address => "0x1231234a",
new_address => "0x1234234d",
source => "sym"
},
jetsons => {
old_address => "0x12712343",
new_address => "0x12142344",
source => "sym"
},
simpsons => {
old_address => "0x12f12347",
new_address => "0x12a42348",
source => "dwarf"
},
);
my $href = \%hoh;
my $queue= Thread::Queue->new($href);
my $t = threads->create('start_sub');
my $result = $t->join;
sub start_sub {
print "items on queue = " . $queue->pending() . "\n";
while( $queue->pending() ) {
my $item = $queue->dequeue_nb();
#
## dequeue_nb returns undef when queue empty
if( $item ) {
print "Doing work in thread " . threads->tid() . " on:\n";
print Dumper($item);
print "Done =====================\n"
}
}
}
But it will be better if you use reference instead of hash. Use an arrefref that contain hashrefs. That would be more efficient.
This for your current code.
sub dequeue_nb{
my $key_of_first_item = (keys %hoh)[0];#random order
my $item = $hoh{$key_of_first_item};
delete $hoh{$key_of_first_item};
return $item;
regards,