我在下面看到了一些繁重的规定,最后我们得到了一些@hits
,我们只需要返回一个:
if ($#hits > 0)
{
my $highestScore = 0;
my $chosenMatch = "";
for $hit (@hits)
{
my $currScore = 0;
foreach $k (keys %{$hit})
{
next if $k eq $retColumn;
$currScore++ if ($hit->{$k} =~ /\S+/);
}
if ($currScore > $highestScore)
{
$chosenMatch = $hit;
$highestScore = $currScore;
}
}
return ($chosenMatch);
}
elsif ($#hits == 0)
{
return ($hits[0]);
}
我的眼睛已经满了,我希望简化上面的代码,我想出了:
return reduce {grep /\S+/, values %{$a} > grep /\S+/, values %{$b} ? $a : $b} @matches;
使用课程后use
,List::Util
我想知道简洁版本是否比原版本有效和/或优势。此外,还有一个条件被跳过:if $k eq $retColumn
,我怎样才能有效地将其传入?
答案 0 :(得分:4)
我想知道简洁版本是否比原版本有效和/或优势
简洁版的效率低于原版,因为它会计算每个元素的得分两次,但它确实具有可读性优势。
以下内容保持了可读性增益(甚至增加了一些):
sub get_score {
my ($match) = @_;
my @keys = grep { $_ ne $retColumn } keys %$match;
my $score = grep { /\S/ } @{$match}{ @keys };
return $score;
}
return reduce { get_score($a) > get_score($b) ? $a : $b } @matches;
您可以查看该子组件的任何部分并在不环顾四周的情况下理解它。您需要理解代码的最少上下文,它的可读性就越高。
如果确实需要提高效率,可以避免使用Schwartzian变换在每次输入上调用get_score
两次。与许多优化一样,您将获得可读性,但至少它是惯用的(众所周知且因此可识别)。
return
map { $_->[0] }
reduce { $a->[1] > $b->[1] ? $a : $b }
map { [ $match, get_score($match) ] }
@matches;
答案 1 :(得分:4)
有一句名言:
“过早优化是所有邪恶的根源” - 唐纳德克努特
几乎总是如此,使代码更简洁实际上并没有对效率产生太大影响,并且可能会对可读性和可维护性造成重大损失。
算法很重要,代码布局......不是真的。像reduce
,map
和grep
之类的东西仍在循环中 - 他们只是在幕后这样做。使用它们几乎没有效率,你刚刚在文件中保存了一些字节。如果它们使您的代码更清晰,那就没问题,但这应该是您最重要的考虑因素。
请 - 先保持清醒,始终保持清醒。让你的算法变得更好。不要担心用grep
或map
替换显式循环,除非这些事情使您的代码更清晰。
为了建设性的利益:
strict
和warnings
非常重要。真的非常重要。回答你原来的问题:
我想知道简洁版本是否比原版本有效和/或优势
不,我认为如果有相反的事情。除了分析代码速度之外,经验法则是查看循环的数量和大小 - 单个代码块很少有很大差异,但运行它很多次(不必要地)是你效率低下的地方。
在您的第一个示例中 - 您有两个循环,foreach
循环内的for
循环。看起来您遍历了@hits
数据结构一次,然后“打开”它以获取内层。
在您的第二个示例中,您的grep
都是循环,而您的reduce
也是。如果我正确地阅读它,那么它将多次遍历您的数据结构。 (因为您grep
values $a
和$b
- 这些将会多次应用。)
因此,我不认为你通过做你所做的事情已经获得了可读性或效率。但是你已经做了一个功能,这将使未来的维护程序员必须非常努力地思考。采取另一个引用:
“每个人都知道调试的速度是编写程序的两倍。所以,如果你在编写程序时就像你一样聪明,那么你将如何调试呢?” - Brian Kernighan