如何根据另一个哈希的键/值删除[子]哈希?
假设我有两个哈希值。其中一个包含一组数据,只需要保留另一个哈希中显示的内容。
例如,
my %hash1 = (
test1 => { inner1 => { more => "alpha", evenmore => "beta" } },
test2 => { inner2 => { more => "charlie", somethingelse => "delta" } },
test3 => { inner9999 => { ohlookmore => "golf", somethingelse => "foxtrot" } }
);
my %hash2 = (
major=> { test2 => "inner2",
test3 => "inner3" } );
我想做的是,如果 hash1 中的整个子哈希不作为 hash2{major} 中的键/值存在,则删除它,最好没有模块。 “innerX”中包含的信息并不重要,它只是必须保留(除非要删除子哈希,然后它就会消失)。
在上面的示例中,执行此操作后,hash1 将如下所示:
my %hash1 = (
test2 => { inner2 => { more => "charlie", somethingelse => "delta" } },
);
它删除 hash1{test1} 和 hash1{test3},因为它们与 hash2 中的任何内容都不匹配。
这是我目前尝试过的方法,但它不起作用。这也可能不是最安全的做法,因为我在尝试删除哈希值时循环遍历哈希值。不过我正在删除每个应该没问题的吗?
这是我尝试这样做,但是 perl 抱怨:
Can't use string ("inner1") as a HASH ref while "strict refs" in use at
while(my ($test, $inner) = each %hash1)
{
if(exists $hash2{major}{$test}{$inner})
{
print "$test($inner) is in exists.\n";
}
else
{
print "Looks like $test($inner) does not exist, REMOVING.\n";
#not to sure if $inner is needed to remove the whole entry
delete ($hash1{$test}{$inner});
}
}
Lets assume I have two hashes. One of them contains a set of data that only needs to keep things that show up in the other hash.
e.g.
my %hash1 = (
test1 => { inner1 => { more => "alpha", evenmore => "beta" } },
test2 => { inner2 => { more => "charlie", somethingelse => "delta" } },
test3 => { inner9999 => { ohlookmore => "golf", somethingelse => "foxtrot" } }
);
my %hash2 = (
major=> { test2 => "inner2",
test3 => "inner3" } );
What I would like to do, is to delete the whole subhash in hash1 if it does not exist as a key/value in hash2{major}, preferably without modules. The information contained in "innerX" does not matter, it merely must be left alone (unless the subhash is to be deleted then it can go away).
In the example above after this operation is preformed hash1 would look like:
my %hash1 = (
test2 => { inner2 => { more => "charlie", somethingelse => "delta" } },
);
It deletes hash1{test1} and hash1{test3} because they don't match anything in hash2.
Here's what I've currently tried, but it doesn't work. Nor is it probably the safest thing to do since I'm looping over the hash while trying to delete from it. However I'm deleting at the each which should be okay?
This was my attempt at doing this, however perl complains about:
Can't use string ("inner1") as a HASH ref while "strict refs" in use at
while(my ($test, $inner) = each %hash1)
{
if(exists $hash2{major}{$test}{$inner})
{
print "$test($inner) is in exists.\n";
}
else
{
print "Looks like $test($inner) does not exist, REMOVING.\n";
#not to sure if $inner is needed to remove the whole entry
delete ($hash1{$test}{$inner});
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
你很接近。请记住,
$hash2{major}{$test}
是标量,而不是哈希引用。以
$delete = 0, ...
开头的行有点可爱。相当于 $delete = 0; last; 在另一个条件中,但它已经嵌套了两次。不想建造一个 matryoshka 娃娃,我使用了一个 语句修饰符,但顾名思义,它修改单个语句。这就是 Perl 的逗号运算符 发挥作用的地方:
在本例中,左侧参数是表达式
$delete = 0
,右侧参数是last
。该条件可能看起来不必要的繁琐,但
在探测
%hash2
中未提及的测试(例如 test1/inner1)时会产生未定义值警告。 使用如果
%hash2
中提到的测试的“内部名称”是一个错误值(例如字符串“0”
),则 会错误地删除该测试。是的,在这里使用exists
可能会不必要地繁琐,但由于不知道你的实际哈希键,我选择了保守的路线。输出:
尽管您没有违反它,但请注意以下与使用
相关的警告每个
:更新:像数组一样搜索哈希(印象深刻你的 CS 书呆子朋友说“……线性而不是对数”)是一个危险信号,上面的代码就是这样做的。一种更好的方法与 Penfold 的答案类似,
它以良好的声明式风格描述了
%hash1
所需的内容,即%hash1
的一级键> 应该在$hash2{major}
中提及,并且$hash2{major}
中每个一级键对应的值本身应该是该键的子键%hash1
中(哇,令人眼花缭乱。我们需要多个英语占位符变量!)
+($_ => $hash1{$_})
中的一元加号消除了歧义对于糟糕的解析器来说,它知道我们希望将表达式视为“对”。有关其他信息,请参阅 关于map
的 perlfunc 文档的末尾可能需要这样做的情况。You were close. Remember that
$hash2{major}{$test}
is a scalar, not a hash reference.The line beginning with
$delete = 0, ...
is a bit cutesy. It's equivalent to$delete = 0; last;
within another conditional, but it was already nested twice. Not wanting to build a matryoshka doll, I used a statement modifier, but as the name suggests, it modifies a single statement.That's where Perl's comma operator comes in:
In this case, the left argument is the expression
$delete = 0
, and the right argument islast
.The conditional might seem needlessly fussy, but
produces undefined-value warnings when probing for tests not mentioned in
%hash2
(test1/inner1, for example). Usingwould incorrectly delete a test mentioned in
%hash2
if its "inner name" were a false value such as the string"0"
. Yes, usingexists
here may be needlessly fussy, but not knowing your actual hash keys, I chose the conservative route.Output:
Although you don't violate it, be aware of the following caveat related to using
each
:Update: Searching hashes as though they were arrays (impress your CS nerd friends by saying “… linearly rather than logarithmically”) is a red flag, and the code above does just that. A better approach, which turns out to be similar to Penfold's answer, is
In nice declarative style, it describes the desired contents of
%hash1
, namely%hash1
should be mentioned in$hash2{major}
, and$hash2{major}
corresponding to each first-level key should itself be a subkey of that key back in%hash1
(Wow, dizzying. We need multiple placeholder variables in English!)
The unary plus in
+($_ => $hash1{$_})
disambiguates for the poor parser so it knows we want the expression treated as a “pair.” See the end of the perlfunc documentation onmap
for other cases when this may be necessary.您可以将其作为单行代码来完成,因为delete() 将采用一组键。这并不像我最初想象的那么容易,但现在我已经正确地阅读了这个问题......
You can do it as a one-liner, all because delete() will take an array of keys. It's not quite as easy as I first thought, but now I've read the problem properly...
这是有效的,因为我们本质上是在三个独立的阶段中列出我们想要/不想要的东西的列表:
这样,在我们准备好之前,我们永远不会更改主哈希。如果 %hash1 包含许多键,我们将使用大量内存。如果您担心这一点,您可以这样做:
这个之所以有效,是因为我们不是在散列上迭代,而是在其密钥的存储副本上迭代。
This works because we essentially work out the lists of things we want/don't want in three independent stages:
This way we never alter the primary hash until we're ready to do so. If %hash1 contains many keys, we're going to use a lot of memory. If you're worried about that, you'd do something like this:
This one works because we're not iterating over the hash, but over a stored copy of its keys.
这就是我会这样做的方式:(第三次尝试就是魅力)
This is the way I would do it: (Third try's the charm)