有一系列哈希值,
my @arr = get_from_somewhere();
@arr内容(例如)是:
@arr = (
{ id => "id2", requires => 'someid', text => "another text2" },
{ id => "xid4", requires => 'id2', text => "text44" },
{ id => "someid", requires => undef, text => "some text" },
{ id => "id2", requires => 'someid', text => "another text2" },
{ id => "aid", requires => undef, text => "alone text" },
{ id => "id2", requires => 'someid', text => "another text2" },
{ id => "xid3", requires => 'id2', text => "text33" },
);
需要类似的东西:
my $texts = join("\n", get_ordered_texts(@arr) );
soo需要写一个sub,从哈希中返回text
s的数组, - 依赖顺序,所以从上面的例子中得到:
"some text", #someid the id2 depends on it - so need be before id2
"another text2", #id2 the xid3 and xid4 depends on it - and it is depends on someid
"text44", #xid4 the xid4 and xid3 can be in any order, because nothing depend on them
"text33", #xid3 but need be bellow id2
"alone text", #aid nothing depends on aid and hasn't any dependencies, so this line can be anywhere
正如你所看到的,在@arr中可能有一些重复的“行”,(上例中的“id2”),只需要输出任何id。
尚未提供任何代码示例,因为我们不知道如何开始。 ( 存在一些可用于解决方案的CPAN模块?
有人能指出我正确的方向吗?
答案 0 :(得分:13)
使用Graph:
use Graph qw( );
my @recs = (
{ id => "id2", requires => 'someid', text => "another text2" },
{ id => "xid4", requires => 'id2', text => "text44" },
{ id => "someid", requires => undef, text => "some text" },
{ id => "id2", requires => 'someid', text => "another text2" },
{ id => "aid", requires => undef, text => "alone text" },
{ id => "id2", requires => 'someid', text => "another text2" },
{ id => "xid3", requires => 'id2', text => "text33" },
);
sub get_ordered_recs {
my %recs;
my $graph = Graph->new();
for my $rec (@_) {
my ($id, $requires) = @{$rec}{qw( id requires )};
$graph->add_vertex($id);
$graph->add_edge($requires, $id) if $requires;
$recs{$id} = $rec;
}
return map $recs{$_}, $graph->topological_sort();
}
my @texts = map $_->{text}, get_ordered_recs(@recs);
答案 1 :(得分:4)
一个有趣的问题。
这是我的第一轮解决方案:
sub get_ordered_texts {
my %dep_found; # track the set of known dependencies
my @sorted_arr; # output
my $last_count = scalar @_; # infinite loop protection
while (@_ > 0) {
for my $value (@_) {
# next unless we are ready for this text
next if defined $value->{requires}
and not $dep_found{ $value->{requires} };
# Add to the sorted list
push @sorted_arr, $value->{text};
# Remember that we found it
$dep_found{ $value->{id} }++;
}
if (scalar @_ == $last_count) die "some requirements don't exist or there is a dependency loop";
$last_count = scalar @_;
}
return \@sorted_arr;
}
这不是非常有效,可能会在O(n log n)
时间内运行,但如果你没有庞大的数据集,那可能就行了。
答案 2 :(得分:2)
我会使用有向图来表示依赖树,然后走图。我使用Graph.pm
做了类似的事情每个哈希值都是一个图形顶点,边缘代表依赖关系。这有额外的好处,支持将来更复杂的依赖关系,以及提供使用图形的快捷功能。
答案 3 :(得分:1)
你没有说依赖关系的做法是彼此“独立”的。
E.g。 id1需要id2; id3需要id4; id3需要id5。订单应该是什么? (4/5之前的2和3之前的1除外)
你想要的基本上是依赖关系树(有向图)的BFS(广度优先搜索)(或森林取决于#1的答案 - 森林是一组非连接树)。
要做到这一点:
查找所有根节点(自身没有需求的ID)
您可以通过在数据结构上使用grep
对所有ID进行哈希来轻松完成此操作
将所有这些根模式放入起始数组中。
然后实施BFS。如果您需要帮助在Perl中使用数组和循环实现基本BFS,请提出单独的问题。可能有一个CPAN模块,但算法/代码相当简单(至少一次你写了一次:)