perl ...使用@array项目创建一个%哈希的水平儿童
我一直在这段时间里敲我的头,并搜索了许多方式。我敢肯定,这将归结为真正的基础。
我有一个@array中的数据,我想以%哈希移动到树上。
这可能更适合JSON?但是我以前从未研究过,也不需要节省/还原这些信息。
需求:
创建一个可以彼此嵌套的USB设备的依赖树,可以通过轮毂(设备B)和最后的根(Devicea)跟踪终点(Devicec)。
示例:
简化(我希望...这不是来自实际更长脚本):
我想以这种格式转换一个数组:
my @array = ['deviceA','deviceB','deviceC'];
多维哈希等于:
my %hash = ('deviceA' => { 'deviceB' => { 'deviceC' => '' } } )
那会倾倒:
$VAR1 = {
'deviceA' => {
'deviceB' => {
'deviceC' => ''
}
}
};
仅查看单个设备, 't有必要,但我正在建立一个iommu -> PCI设备 - >包含许多设备的USB图。
注意:
- 我正在尝试避免安装CPAN模块,因此脚本是类似的系统(Proxmox ve),
- 最后一个设备(上面的Devicec)没有孩子
- value''是可以的
- Undef可能会起作用
- 混合类型可以工作,但我需要知道如何设置
- 我永远不需要修改或操纵哈希后,
- 我不知道正确的方法重复@array以填充百分比的孩子。 *我想要每个USB设备的水平数据,
- 我会切换到对象/软件包,但是每个设备都可以拥有不同的孩子(或无),因此知道对象名称不可行
- 一些USB设备没有孩子(根轮)...类似于%哈希=('devicea'=>'')
- 有些有1个孩子是最终设备...类似于%hash =('devicea'=> {'deviceb'=>''})
- 有些通过其他集线器之间有多个步骤...类似于%hash =('devicea'=> {'deviceb'=> {'devicec'=>''}}) 或更多
起点:
这是基本的且不完整的,但会运行:
#!/usr/bin/perl
use strict;
use warnings;
use Data::Dumper qw(Dumper);
# data in from parsing usb device path:
my @array = ['deviceA','deviceB','deviceC'];
# needs to be converted to:
my %hash = ('deviceA' => { 'deviceB' => { 'deviceC' => '' } } );
print "\n\%hash:\n" . Dumper \%hash;
pseudo-code
本节没有任何形式的工作代码。我只是想记下我的想法。我知道格式是错误的,我已经尝试了多种方法来创建此功能,并且 我看起来甚至是Dumber 显示我的所有尝试: )
我是Refs的新手,我不会尝试在这里找到它。下面的想法是:
- @array中的每个项目:
- 创建一种可以使用下一个迭代来放置下一个孩子的方法(当前哈希的参考或副本)
- 作为上一个迭代的孩子,附上一个空价值(如果有进一步的迭代,可以附加) )
my @array = ['deviceA','deviceB','deviceC'];
my %hash = {};
my %trackref;
for (@array) {
%trackref = %hash; # a copy of the existing that won't change when %hash updates
$hash{last_child} ::append_child:: $_;
}
I've been banging my head on this awhile and searched many ways. I'm sure this is going to boil down to being really basic.
I have data in an @array that I want to move to a tree in a %hash.
This might be something more appropriate to JSON? But I haven't delved into it before and I don't need to save out/restore this information.
Desire:
Create a dependent tree of USB devices that can nest under each other that can track the end point (deviceC) through a hub (deviceB) and finally the root (deviceA).
Example:
Simplified (I hope ... this isn't from the actual longer script):
I want to convert an array in this format:
my @array = ['deviceA','deviceB','deviceC'];
to multidimensional hashes equal to:
my %hash = ('deviceA' => { 'deviceB' => { 'deviceC' => '' } } )
that would dump like:
$VAR1 = {
'deviceA' => {
'deviceB' => {
'deviceC' => ''
}
}
};
For just looking at a single device this isn't necessary, but I'm building out an IOMMU -> PCI Device -> USB map that contains many devices.
NOTES:
- I'm trying to avoid installing CPAN modules so the script is to similar systems (Proxmox VE)
- The last device (deviceC above) has no children
- value '' is fine
- undef would probably work
- mixing the types would work but I need to know how to set that
- I will never need to modify or manipulate the hash once created
- I don't know the right way to recurse the @array to populate the %hash children. * I want the data horizontal for each USB device
- I'd switch to an Object/package but each device can have a different set of children (or none) making it infeasible to know Object names
- Some USB devices have no children (root hubs) ... similar to %hash = ('deviceA' => '')
- Some have 1 child that is the final device ... similar to %hash = ('deviceA' => { 'deviceB' =>'' } )
- Some have multiple steps between the root via additional hub(s) ... similar to %hash = ('deviceA' => { 'deviceB' => { 'deviceC' => '' } } ) or more
Starting point :
This is basic and incomplete but will run:
#!/usr/bin/perl
use strict;
use warnings;
use Data::Dumper qw(Dumper);
# data in from parsing usb device path:
my @array = ['deviceA','deviceB','deviceC'];
# needs to be converted to:
my %hash = ('deviceA' => { 'deviceB' => { 'deviceC' => '' } } );
print "\n\%hash:\n" . Dumper \%hash;
Pseudo-code
This section is NOT working code in any form. I'm just trying to make a note of what I'm thinking. I know the format is wrong, I've tried multiple ways to create this and I'd look even dumber showing all of my attempts :)
I'm very new to refs and I'm not going to try and get that right here. The idea below is:
- For each item in @array:
- Create a way (either a ref or a copy of the current hash) that can be used next iteration to place the next child
- Attach item as a child of the previous iteration with an empty value (that can be appended if there is further iteration)
my @array = ['deviceA','deviceB','deviceC'];
my %hash = {};
my %trackref;
for (@array) {
%trackref = %hash; # a copy of the existing that won't change when %hash updates
$hash{last_child} ::append_child:: $_;
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
您实际上很接近,但是似乎您需要更好地了解参考文献。 perldoc perlref 可能是理解参考文献的好起点。
在查看解决方案之前,您的代码中有一些错误:
my @array = [...];
:[]
创建一个arrayref,而不是阵列,这意味着@array
实际上存储一个标量项目:对另一个数组的引用。使用()
初始化一个数组:my @array =(...);
。我的%hash = {};
:同样,{}
创建hashref,而不是哈希。这意味着该行将单个hashref存储在%hash
中,这将引起此警告:参考可以找到在hash.pl line 上预期的尺寸均匀列表(因为哈希包含键值,您只提供了一个键)。对于简单(即,不是hashref)哈希,请使用()
。但是,在这种情况下,您无需初始化%hash
:我的%hash;
and我的%hash =()
做相同的操作事物(也就是说,创建一个空的哈希)。%trackRef =%hash;
在%hash
中复制hash
in%trackref
。这意味着,与“ TrackRef”的名称相反,%TrackRef
不包含对任何事物的引用,而是%hash
的副本。使用\%hash
创建对%hash
的引用。请注意,如果您已经有hashref,则将其分配给另一个变量将复制引用。例如,如果您做
我的$ hash1 = {};我的$ hash2 = $ hash1
,然后$ hash1
和$ hash2
参考相同的hash。因此,解决这些问题时,我们会得到:
输出:
我所做的主要更改是替换您的
$ hash {last_child} :: append_child :: $ _;
by$ $ TrackRef-> {$ _} = {};
。但是这个想法保持不变:作为上一个迭代的孩子附上一个空白值以重复使用您的单词。为了帮助您更好地理解代码,让我们看看循环中逐步发生的情况:
在第一次迭代之前,
%hash
是空的,$ trackref
参考%哈希
。在第一次迭代中,我们将
devicea =&gt放置; {}
in$ trackRef
(或者,更详细的是,我们将{}
与键devicea
In$ trackRef相关联
)。由于$ trackRef
参考%hash
,因此putsdevicea => {}
在%hash
中。然后,我们存储在$ trackRef
此新的{}
中,这意味着$ trackRef
现在参考$ $ hash { devicea}
。在第二次迭代中,我们将
deviceb =&gt放置; {}
在$ trackref
中。$ TRACKEREF
参考$ hash {devicea}
(我们在上一个迭代中创建的),这意味着%hash
现在是( devicea => {deviceb => {}})
。然后,我们存储在$ TRACKREF
新{}
。等等...
您会注意到,在最内向的哈希中,
{}
与键devicec
关联。当迭代哈希时,因此您可以知道您是否在结束时执行之类的事情,如果(%$ hash)
(而不是(而不是)如果($ hash)
if(如果最后一个{}
将是undef
或''
)。让我知道这是否是一个问题:我们可以添加一些代码将此{}
转换为undef
(另外,您可以自己做,这将是一个很好的习惯习惯参考)次要说明:
@array
和%哈希
是差的数组和哈希名称,因为@
已经指示一个数组和%
已经表示哈希。您可能仅将这些名称用于这个小示例作为您的问题,在这种情况下,没有问题。但是,如果您在实际代码中使用这些名称,请考虑更改它们的更明确的内容...@USB_DEVICES
和%usb_devices_tree
也许?You're actually pretty close, but it seems that you need to understand references a bit better. perldoc perlref is probably a good starting point to understand references.
A few mistakes in your code, before looking at the solution:
my @array = [ ... ];
:[]
creates an arrayref, not an array, which means that@array
actually stores a single scalar item: a reference to another array. Use()
to initialize an array:my @array = ( ... );
.my %hash = {};
: similarly,{}
creates a hashref, not a hash. Which means that this lines stores a single hashref in%hash
, which will cause this warning: Reference found where even-sized list expected at hash.pl line (because a hash contains keys-values and you only provided a key). Use()
for a simple (ie, not a hashref) hash. In this case however, you don't need to initialize%hash
:my %hash;
andmy %hash = ()
do the same thing (that is, create an empty hash).%trackref = %hash;
copies the content of%hash
in%trackref
. Which means that, contrary to what the name "trackref" implies,%trackref
doesn't contain a reference to anything, but a copy of%hash
. Use\%hash
to create a reference to%hash
.Note that if you already have a hashref, then assigning it to another variables copies the reference. For instance, if you do
my $hash1 = {}; my $hash2 = $hash1
, then both$hash1
and$hash2
reference the same hash.So, fixing those issues in your attempt, we get:
Which outputs:
The main change that I did was to replace your
$hash{last_child} ::append_child:: $_;
by$trackref->{$_} = {};
. But the idea remains the same: Attach item as a child of the previous iteration with an empty value to reuse your words.To help you understand the code a bit better, let's see what happens in the loop step by step:
Before the first iteration,
%hash
is empty and$trackref
references%hash
.In the first iteration, we put
deviceA => {}
in$trackref
(or, more pedantically, we associate{}
with the keydeviceA
in$trackref
). Since$trackref
references%hash
, this putsdeviceA => {}
in%hash
. Then, we store in$trackref
this new{}
that we just created, which means that$trackref
now references$hash{deviceA}
.In the second iteration, we put
deviceB => {}
in$trackref
.$trackeref
references$hash{deviceA}
(which we created in the previous iteration), which means that%hash
is now(deviceA => { deviceB => {} })
. We then store in$trackref
the new{}
.And so on...
You'll note that in the innermost hash,
{}
is associated to the keydeviceC
. When iterating of the hash, you can thus know if you are at the end by doing something likeif (%$hash)
(instead of justif ($hash)
if this last{}
would have beenundef
or''
). Let me know if that's an issue: we can add a bit of code to convert this{}
intoundef
(alternatively, you can do it yourself, it will be a good exercise to get used to references)Minor remark:
@array
and%hash
are poor array and hash names, because the@
already indicates an array, and%
already indicates a hash. It's possible that you used those names just for this small example for your question, in which case, no problem. However, if you use those names in your actual code, consider changing them for something more explicit...@usb_devices
and%usb_devices_tree
maybe?