Perl编程实践:数组、哈希与模块开发

内容分享2天前发布
0 0 0

table {
border-collapse: collapse;
width: 100%;
margin-bottom: 1rem;
}
th, td {
border: 1px solid #ddd;
padding: 8px;
text-align: left;
}
th {
background-color: #f2f2f2;
}
tr:nth-child(even) {
background-color: #f9f9f9;
}
pre {
background-color: #f8f8f8;
padding: 15px;
border-radius: 4px;
overflow-x: auto;
}

1、创建一个包含值 Andrew、Andy 和 Kaufman 的数组,并编写一个程序来打印 Andrew “Andy” Kaufman。

以下是实现此功能的 Perl 代码:


use strict;
use warnings;
my @array = ('Andrew', 'Andy', 'Kaufman');
print $array[0]. ' “'. $array[1]. '” '. $array[2]. "
";

上述代码首先创建了一个包含指定值的数组,然后通过索引访问数组元素并按要求的格式打印出来。

2、创建一个哈希,键为水果名称,值为它们的常见颜色,然后将每个键/值对作为单独的一行打印出来,格式类似于“香蕉是黄色的”。

以下代码展示了如何实现:


use strict;
use warnings;
use diagnostics;
my %color_for = ( 
    bananas => 'yellow', 
    apples => 'red', 
    oranges => 'orange',
);
for my $fruit (keys %color_for) { 
    my $color = $color_for{$fruit};
    print "$fruit are $color
";
}

3、根据华氏温度数组 @fahrenheit (0, 32, 65, 80, 212) 创建摄氏温度数组 @celsius。

要创建

@celsius

数组,需要将

@fahrenheit

数组中的每个华氏温度值转换为摄氏温度值。转换公式是先减去 32,然后乘以 5/9。以下是实现代码:


my @fahrenheit = ( 0, 32, 65, 80, 212 );
my @celsius = map { ( $_ - 32 ) * 5 / 9 } @fahrenheit;

4、给定一个包含华氏温度值的数组,创建一个新数组@celsius,其中包含转换为摄氏度的华氏温度。记住,要将华氏温度转换为摄氏温度,必须先减去32,然后将结果乘以5/9。

可以使用以下代码创建

@celsius

数组:


my @fahrenheit = ( 0, 32, 65, 80, 212 );
my @celsius = map { ($_ - 32) * 5/9 } @fahrenheit;

5、如何计算数组@numbers中元素的总和

可以使用如下代码:


my @numbers = qw< 3 9 0 7 8 >;
my $total = 0;
$total += $_ foreach @numbers;

6、如何让代码打印的1 – 10数字在不同行输出

在许多编程语言中,可使用循环结合换行符来实现。以Python为例,代码如下:


for i in range(1, 11):
    print(i)

在上述代码中,

range(1, 11)

生成从1到10的整数序列,

print(i)

会将每个数字打印到单独一行。

7、编写代码计算数组@numbers中元素的总和与平均值并输出

以下是使用 Perl 语言实现计算数组

@numbers

中元素总和与平均值并输出的代码:


my @numbers = (28, 49, 1000, 4, 25, 49, 529);
my $sum = 0;
foreach my $num (@numbers) {
    $sum += $num;
}
my $average = $sum / scalar(@numbers);
print "总和: $sum
";
print "平均值: $average
";

对于不同的数组元素,只需修改

@numbers

中的值即可。

8、找出代码中C – style for循环的逻辑错误并改正

代码中第一个 C – style for 循环示例打印 0 到 9,逻辑正确;第二个循环逻辑有问题,它打印的是 1 到 10,而非 0 到 9。错误在于先执行了

$i++

再打印。改正方法是先打印

$i

再执行

$i++

,修改后的代码如下:


my $i = 0;
for ( ; $i < 10; ) {
    print "$i
";
    $i++;
}

9、在代码中,对哈希表%stat_for中每个键对应的值进行随机赋值,随机值的生成规则为:将两个1 – 6的随机整数相加再加2,且随机值需大于等于6。请添加相应代码实现该功能。


foreach my $stat (keys %stat_for) {
    my $random = 2 + int(rand(6)) + int(rand(6));
    redo if $random < 6;
    $stat_for{$stat} = $random;
}

10、编写完整代码,对哈希表%stat_for中每个键对应的值进行随机赋值,若随机值小于6则重新赋值,并输出结果


my %stat_for = ( strength => undef, intelligence => undef, dexterity => undef, );
foreach my $stat (keys %stat_for) {
    my $random;
    do {
        $random = 2 + int(rand(6)) + int(rand(6));
    } while ($random < 6);
    $stat_for{$stat} = $random;
}
print <<"END_CHARACTER";
Strength: $stat_for{strength}
Intelligence: $stat_for{intelligence}
Dexterity: $stat_for{dexterity}
END_CHARACTER

11、使用两种方式创建数组并赋值,一种不使用分组括号,另一种使用逗号创建列表

在Perl中,不使用分组括号创建数组并赋值可直接用

qw

快捷方式,如:


@array = qw(value1 value2 value3);

使用逗号创建列表来赋值数组的方式为:


@array = ('value1', 'value2', 'value3');

12、对于给定的分数哈希表,如何使用不同方法获取 Jim 和 Mary 的分数,以及分析使用切片时的问题和解决办法

给定分数哈希表如下:


my $score_for = { jim => 89, mary => 73, alice => 100, bob => 83 };

获取 Jim 和 Mary 分数的方法有两种:

使用切片:

perl
my ( $jim, $mary ) = @$score_for{ qw{jim mary} };
print "$jim $mary";

单独赋值:

perl
$jim = $score_for->{jim};
$mary = $score_for->{mary};
print "$jim $mary";

使用切片时的问题:写

%$score_for{ ... }

是错误的。

解决办法:

使用

@

符号表示获取变量列表,如

@$score_for{ ... }

;

不使用切片,而是单独赋值,许多程序员认为这种方法更简洁。

13、编写一个子程序来计算传入数字的平均值,并计算 1、5、18、3、5 这些数字的平均值

以下是实现该功能的代码:


use Scalar::Util 'looks_like_number';
use Carp 'croak';

sub average {
    my @numbers = @_;
    my $total = 0;
    foreach my $number (@numbers) {
        if ( not looks_like_number($number) ) {
            croak "$number doesn't look like a number";
        } else {
            $total += $number;
        }
    }
    return $total / @numbers;
}

print average(1, 5, 18, 3, 5);

14、编写一个子程序,该子程序接受一个数字作为参数,并返回一个新的子程序,新子程序接受一个数字并返回该数字与原参数的乘积

以下是使用 Perl 实现该功能的代码:


sub multiplier_factory {
    my $factor = shift;
    return sub {
        my $number = shift;
        return $number * $factor;
    };
}

使用示例:


my $multiply_by_five = multiplier_factory(5);
print $multiply_by_five(3); # 输出 15

15、编写一个递归子程序来计算一组数字的总和

以下是使用 Perl 编写的递归子程序来计算一组数字的总和的示例代码:


sub sum_recursive {
    my @numbers = @_;
    if (scalar @numbers == 0) {
        return 0;
    } else {
        my $first = shift @numbers;
        return $first + sum_recursive(@numbers);
    }
}

# 测试代码
my @nums = (1, 2, 3, 4, 5);
my $result = sum_recursive(@nums);
print $result; # 输出 15

在这个代码中,

sum_recursive

子程序接收一组数字作为参数。如果输入的数组为空,它返回 0;否则,它取出数组的第一个元素,并递归调用自身来计算剩余元素的总和,最后将第一个元素与剩余元素的总和相加。

16、编写一个程序,从标准输入读取内容并打印出来

在 Perl 中可以使用如下简单程序实现从标准输入读取内容并打印出来:


use strict;
use warnings;
while (my $line = <STDIN>) {
    print $line;
}

将上述代码保存为一个

.pl

文件,例如

read_print.pl

,然后在命令行中运行

perl read_print.pl

,之后输入内容,按回车键即可看到输入的内容被打印出来,输入结束后可以按

Ctrl + D

(在 Windows 系统中按

Ctrl + Z

然后回车)结束输入。

17、对数组 ( 0x23, 0xAA, 0xaa, 0x01, 0xfB ) 进行降序数字排序,并考虑以十六进制形式输出排序结果

在大多数编程语言中,可先将十六进制数转换为十进制进行排序,再转换回十六进制输出。以 Python 为例,代码如下:


arr = [0x23, 0xAA, 0xaa, 0x01, 0xfB]
arr.sort(reverse=True)
hex_arr = [hex(num) for num in arr]
print(hex_arr)

运行结果为

['0xfb', '0xaa', '0xaa', '0x23', '0x1']

18、从数组 @list 中找出唯一的元素

可使用

grep

语句实现。示例代码如下:


my @list = qw( bob sally Andromalius sally bob ned Andromalius );
my %seen;
my @unique_list = grep {!$seen{$_}++ } @list;

最终

@unique_list

数组中即为唯一的元素。

19、对数组 @employees 进行筛选(工作年限大于 1 年)、排序(按姓氏排序),并将结果转换为 ‘名字 姓氏’ 的形式,同时用 for 循环实现该功能。

以下是使用 for 循环重写的代码:


sub by_last_name {
  $a->{last_name} cmp $b->{last_name}
};

my @names = ();
my @sorted_employees = sort by_last_name @employees;

for my $employee (@sorted_employees) {
  if ($employee->{years} > 1) {
    push @names, "$employee->{first_name} $employee->{last_name}";
  }
}

这段代码首先定义了按姓氏排序的子程序

by_last_name

,然后对

@employees

数组进行排序得到

@sorted_employees

。接着使用 for 循环遍历排序后的数组,筛选出工作年限大于 1 年的员工,并将其名字和姓氏组合成字符串添加到

@names

数组中。

20、添加 Convert::Distance::Metric 后,lib/ 目录应呈现怎样的文件布局


lib/
└── Convert
    └── Distance
        ├── Imperial.pm
        └── Metric.pm

21、编写一个名为Convert::Distance::Metric的模块,该模块包含以下子例程:kilometers_to_meters(公里转米)、meters_to_kilometers(米转公里)。使这些子例程可选择性导出,并且允许人们使用

use Convert::Distance::Metric ":all";

导入所有子例程。


package Convert::Distance::Metric;

use strict;
use warnings;

our $VERSION = '0.01';

use Exporter 'import';
our @EXPORT_OK = qw( kilometers_to_meters meters_to_kilometers );
our %EXPORT_TAGS = ( all => @EXPORT_OK );

use constant METERS_PER_KILOMETER => 1000;

sub meters_to_kilometers {
    my $meters = shift;
    return $meters / METERS_PER_KILOMETER;
}

sub kilometers_to_meters {
    my $kilometers = shift;
    return $kilometers * METERS_PER_KILOMETER;
}

1; # Don’t forget that trailing 1!

22、添加Convert::Distance::Metric后,查看lib/目录的文件布局以及MANIFEST的内容。


添加Convert::Distance::Metric后,lib/目录的文件布局如下:

lib/

└── Convert/

└── Distance/

├── Imperial.pm

└── Metric.pm



MANIFEST内容如下:

Changes

lib/Convert/Distance/Imperial.pm

lib/Convert/Distance/Metric.pm

Makefile.PL

MANIFEST

README

t/00-load.t

t/manifest.t

t/pod-coverage.t

t/pod.t


23、在Convert::Distance::Metric模块中添加完整的POD文档,包含以下部分:模块名称(NAME)、简要代码片段展示使用方法(SYNOPSIS)、模块用途描述(DESCRIPTION)、模块导出内容的可选列表(EXPORT)、每个子例程的详细描述(FUNCTION)、已知的错误及如何报告新错误(BUGS)、指向Convert::Distance::Imperial的链接(SEEALSO)、模块作者(AUTHOR)、模块的许可条款(LICENSE)。并通过perldoc lib/Convert/Distance/Metric.pm验证POD输出,也可运行podchecker lib/Convert/Distance/Metric.pm检查POD中的错误。

在模块中添加如下POD内容:


__END__

=head1 NAME

Convert::Distance::Metric - Convert kilometers to meters and back

=head1 SYNOPSIS

    use Convert::Distance::Metric ":all";
    print kilometers_to_meters(7);
    print meters_to_kilometers(3800);

=head1 DESCRIPTION

This is a simple module to convert kilometers to meters and back. It’s mainly here to show how modules are built and documented.

=head1 EXPORT

The following functions may be exported on demand. You can export all of them with:

    use Convert::Distance::Metric ':all';

=over 4

=item kilometers_to_meters

Converts kilometers to meters.

=item meters_to_kilometers

Converts meters to kilometers.

=back

=head1 BUGS

No known bugs at this time.

=head1 SEE ALSO

L<Convert::Distance>, L<perlfunc>

=head1 AUTHOR

Your Name <your.email@example.com>

=head1 LICENSE

This module is free software; you can redistribute it and/or modify it under the same terms as Perl itself.

还需添加FUNCTION、BUGS、SEEALSO、AUTHOR、LICENSE等部分的具体内容,之后使用

perldoc lib/Convert/Distance/Metric.pm

验证POD输出,运行

podchecker lib/Convert/Distance/Metric.pm

检查POD错误。

24、编写一个简短的程序,将3.5千米转换为米,并将结果再转换回千米。假设存在一个名为Convert::Distance::Metric的模块,该模块提供了kilometers_to_meters和meters_to_kilometers两个函数,分别用于千米到米和米到千米的转换。


use Convert::Distance::Metric ":all";

my $meters = kilometers_to_meters(3.5);
my $kilometers = meters_to_kilometers($meters);

print "3.5千米转换为米是:$meters 米
";
print "转换回千米是:$kilometers 千米
";

25、编辑Convert – Distance – Imperial发行版中的t/00 – load.t测试程序,尝试添加一个测试来验证是否可以加载Convert::Distance::Metric模块。

可在

t/00 - load.t

中添加相关测试代码,然后使用


prove -lv t/00 - load.t

检查是否有效,或者运行


perl makefile.pl
make
make test

26、指出代码中 new() 构造函数存在的问题

在示例的

new()

构造函数中,使用了单参数的

bless

,即只对引用进行了祝福,但未指定将其祝福到哪个类中。此时,Perl 会将对象祝福到当前包中,这被认为是不良形式。因为后续若需要从该类继承并复用

new()

构造函数时,会因它将引用祝福到当前类而无法实现。

27、请编写一个 User 类,要求包含 username 和 password 属性,password 属性需要进行 MD5 加密,并且提供一个方法用于验证密码是否正确。


package User;
use Moose;
use Digest::MD5 'md5_hex';
use namespace::autoclean;

has username => ( is => 'ro', isa => 'Str', required => 1 );
has password => ( is => 'ro', isa => 'Str', writer => '_set_password', );

sub BUILD {
    my $self = shift;
    $self->_set_password(md5_hex($self->password));
}

sub password_eq {
    my ( $self, $password ) = @_;
    $password = md5_hex($password);
    return $password eq $self->password;
}

__PACKAGE__->meta->make_immutable;
1;

28、编写一个 unique 函数,该函数接受一个数组作为参数,返回数组中唯一的元素,并且元素的顺序应该与它们在原始数组中出现的顺序相同。

以下是实现该功能的代码:


sub unique {
    my @array = @_;
    my %seen;
    my @unique;
    foreach my $element (@array) {
        push @unique, $element unless $seen{$element}++;
    }
    return @unique;
}

29、原 unique 函数返回的元素顺序是随机的,如何修改代码使它返回的元素按顺序排列。

可以使用哈希表和数组结合的方式来实现。代码示例如下:


my @array = ( 3, 4, 1, 4, 7, 7, 4, 1, 3, 8 );
my %seen;
my @ordered;

foreach my $element (@array) {
    if ( not $seen{$element}++ ) {
        push @ordered, $element;
    }
}

foreach my $element (@ordered) {
    print "Ordered: $element
";
}

这段代码通过遍历数组,利用哈希表

%seen

标记元素是否已出现过,将首次出现的元素按顺序存入数组

@ordered

中,从而实现按顺序输出唯一元素。

© 版权声明

相关文章

暂无评论

none
暂无评论...