解释Perl代码以KB,MB,GB等显示多个字节

use*_*521 7 perl

给定了一些字节,它将其格式化为"字节","KB","MB"或"GB"......但我不明白的是部分:

$_->[1], $_->[0]
Run Code Online (Sandbox Code Playgroud)

是不是传递给地图只是一个哈希数组?那么如何才能有0和1指数呢?

sub fmt {
    my $bytes = shift;

    return (
        sort { length $a <=> length $b                         } 
        map  { sprintf '%.3g%s', $bytes/1024**$_->[1], $_->[0] } 
        [" bytes"=>0],[KB=>1],[MB=>2],[GB=>3]
    )[0];
}
Run Code Online (Sandbox Code Playgroud)

Bor*_*din 7

这是一段糟糕的代码.有人在炫耀

传递给的列表map是这样的:匿名数组列表

[ " bytes" => 0 ], [ KB => 1 ], [ MB => 2 ], [ GB => 3 ]
Run Code Online (Sandbox Code Playgroud)

虽然胖逗号运算符=>经常出现在哈希文字的上下文中,但这并不是一件好事.除了字左手操作数将被隐式引用之外,它普通逗号,相同.没有它,列表将是相同的

[ ' bytes', 0 ], [ 'KB', 1 ], [ 'MB', 2 ], [ 'GB', 3 ]
Run Code Online (Sandbox Code Playgroud)

这是相同的函数,中间map语句的结果扩展为一个单独的数组@variations,我转储Data::Dump它以显示它正在做什么

传递给的列表map是一些匿名数组 - 每个数组都包含后缀字符串以及该字符串对应的1024的相应功率.该return陈述只是选择最短的表示

use strict;
use warnings 'all';
use feature 'say';

use Data::Dump;

say fmt(987 * 1024**2);

sub fmt {
        my $bytes = shift;

        my @variations = map { sprintf '%.3g%s', $bytes/1024 ** $_->[1], $_->[0] }
            [ " bytes" => 0 ],
            [ KB => 1 ],
            [ MB => 2 ],
            [ GB => 3 ];

        dd \@variations;

        return ( sort { length $a <=> length $b } @variations ) [0];
}
Run Code Online (Sandbox Code Playgroud)

产量

["1.03e+009 bytes", "1.01e+006KB", "987MB", "0.964GB"]
987MB
Run Code Online (Sandbox Code Playgroud)

我通常使用类似的东西.滑稽动作sprintf是为了确保永远不会显示一个字节的分数

sub fmt2 {
    my ($n) = @_;
    my @suffix = ( '', qw/ K M G T P E / );

    my $i = 0;
    until ( $n < 1024 or $i == $#suffix ) {
        $n /= 1024;
        ++$i;
    }

    sprintf $i ? '%.3g%sB' : '%.0f%sB', $n, $suffix[$i];
}
Run Code Online (Sandbox Code Playgroud)


Ben*_*imm 5

只需一点数学知识,无需任何迭代或巧妙构造的数组即可完成此操作:

my @si_prefix = ('', qw( K M G T P E Z Y ));
sub fmt {
  my $bytes = shift or return '0B';
  my $pow = int log(abs $bytes)/log(1024);
  return sprintf('%3.3g%sB', $bytes / (1024 ** $pow), $si_prefix[$pow]);
}
Run Code Online (Sandbox Code Playgroud)

我们可以通过使用对数基数变化规则轻松确定最接近的 1024 次方: log 1024 ($bytes) = log($bytes) / log(1024)

只是为了好玩,我Benchmark::cmpthese使用问题 @Borodin'sfmt2和我的版本中的代码运行:

Benchmarking 1B
                 Rate    fmt_orig fmt_borodin         fmt
fmt_orig     245700/s          --        -76%        -84%
fmt_borodin 1030928/s        320%          --        -34%
fmt         1562500/s        536%         52%          --

Benchmarking 7.45GB
                 Rate    fmt_orig fmt_borodin         fmt
fmt_orig     224215/s          --        -66%        -84%
fmt_borodin  653595/s        192%          --        -54%
fmt         1428571/s        537%        119%          --

Benchmarking 55.5EB
                 Rate    fmt_orig fmt_borodin         fmt
fmt_orig     207469/s          --        -57%        -83%
fmt_borodin  487805/s        135%          --        -60%
fmt         1219512/s        488%        150%          --
Run Code Online (Sandbox Code Playgroud)