在Perl的空白处拆分

Shi*_*dia 4 perl

我有一个类型的数据 -

500 3.6673656 
----------
1000 3.2707536
----------
1500 3.2356145
----------
2000 3.0495141
----------
2500 3.016674
Run Code Online (Sandbox Code Playgroud)

即时间和距离.我需要将时间分成一个数组,将距离分成另一个数组.通过使用my @line = split( /\s+/, $_);我可以将距离存储在一个数组中,但不能存储时间.有没有其他方法可以将它们分别存储在不同的数组中?

输入来自文件,内容存储在@array.

我的剧本:

    foreach $_ (@array){ 
    if($_ =~ /[@]/) {# do nothing, it's a comment or formatting line} 
    else  {my @line = split( /\s+/, $_);
    print "@line\n";}
}
Run Code Online (Sandbox Code Playgroud)

Dav*_* W. 6

让我们得到所有花哨的裤子:

#! /usr/bin/env perl
#

use strict;
use warnings;
use feature qw(say);

my @array;
while ( my $line = <DATA> ) {
    chomp $line;
    push @array, $line;
}

#
# As two separate arrays (Not so good)
#
my @times;
my @distances;
for my $entry ( @array ) {
    chomp $entry;               # Not needed, but never hurts
    next if $entry =~ /--+$/;   # Next if all dashes
    my ( $distance, $time ) = split /\s+/, $entry;
    push @times, $time;
    push @distances, $distance;
}
say "The first entry as two distinct arrays";
say "Distance: $distances[0]";
say "Time: $times[0]";

#
# As two entries in a single array
#
my @velocities;
for my $entry ( @array ) {
    chomp $entry;               # Not needed, but never hurts
    next if $entry =~ /--+$/;   # Next if all dashes
    my @velocity = split /\s+/, $entry;
    push @velocities, \@velocity;
}
say "The first entry as an array of arrays";
say "Distance: " . $velocities[0]->[0];
say "Time: " . $velocities[0]->[1];
#
# As a hash in an array (Better Still)
# Note: Using regular expression to split
#
my @velocities2;
for my $entry ( @array ) {
    chomp $entry;               # Not needed, but never hurts
    next unless $entry =~ /\s*(\S+)\s+(\S+)/;
    my %velocity;
    $velocity{DISTANCE} = $1;
    $velocity{TIME} = $2;
    push @velocities2, \%velocity;
}
say "The first entry as an array of hashes";
say "Distance: " . $velocities2[0]->{DISTANCE};
say "Time: " . $velocities2[0]->{TIME};
#
# As objects (The best!)
#
my @velocities3;
for my $entry ( @array ) {
    chomp $entry;               # Not needed, but never hurts
    next unless $entry =~ /\s*(\S+)\s+(\S+)/;
    my $distance = $1;
    my $time = $2;
    my $velocity = Local::Velocity->new( $distance, $time );
    push @velocities3, $velocity;
}
say "The first entry as an object";
say "Distance: " . $velocities3[0]->distance;
say "Time: " . $velocities3[0]->time;

package Local::Velocity;

sub new {
    my $class    = shift;
    my $distance = shift;
    my $time     = shift;

    my $self = {};
    bless $self, $class;
    $self->distance( $distance );
    $self->time( $time );
    return $self;
}

sub distance {
    my $self     = shift;
    my $distance = shift;

    if ( defined $distance ) {
        $self->{DISTANCE} = $distance;
    }
    return $self->{DISTANCE};
}

sub time {
    my $self    = shift;
    my $time    = shift;

    if ( defined $time ) {
        $self->{TIME} = $time;
    }
    return $self->{TIME};
}

package main;
__DATA__
500 3.6673656 
----------
1000 3.2707536
----------
1500 3.2356145
----------
2000 3.0495141
----------
2500 3.016674
Run Code Online (Sandbox Code Playgroud)

第一种方式是你问的:两个并行数组.此方法的问题在于您现在必须按顺序保留两个单独的数据结构.如果传递时间和距离,则必须传递两个单独的数据元素.如果修改一个,则必须修改另一个.如果你pushpop一个人,你必须对另一个人这样做.

只有两个,但不是太糟糕,但想象一下,十几个或更多.

第二种方式使用References.引用允许您执行更复杂的数据结构.这将两个条目保持在一个阵列中.现在,您有一个包含两个条目的数组.push一个,你push就是另一个.pop一个,你pop就是另一个.如果将时间和距离传递给子程序,则只需传递一个条目.

第三种方式将参考概念提升了一个档次.您可以使用哈希,而不是使用数组来存储您的两个值.优点是散列中的每个元素都有一个名称.第一个入口或第二个入口是距离吗?没关系,这是标记的条目DISTANCE.与数组或数组相同的优点,但现在,您标记哪个是哪个.想象一个有姓名,电话,地址等的人,你可以看到这个优势.

最后一种方法是使用对象.您可以看到与使用哈希非常相似.您没有哈希或数组.您有一个Local::Velocity包含时间和距离的对象.

它似乎有点复杂,但对象有很多优点:

  • 条目是否DISTANCE,Distance或者distance,并且没有拼写错误的问题是没有问题的distanse.你有一个叫做的方法distance.搞清楚这个名字,你的程序尽职尽责地崩溃,而不是继续处理糟糕的数据.
  • 您可以在不影响程序的情况下修改对象.例如,可能会调用一个子程序velocity来获取对象并返回速度.或许您可能想要为速度添加方向.修改对象不会影响您的程序.

面向对象的Perl允许您创建极其复杂的数据类型,而无需记住您如何构建它们.这就是为什么大多数新模块都是面向对象的.


Axe*_*man 5

拆分线和存储数据是微不足道的.您希望如何存储它以供以后使用是个问题.您可以在空格上拆分线并将其存储为:

my @data =  map { [ split ] } @lines;
Run Code Online (Sandbox Code Playgroud)

默认调用split,拆分 $_空格.

接下来,您可以'@'使用grep 省略这些行:

my @data = map { [ split ] } grep { index( $_, '@' ) == -1 } @lines;
Run Code Online (Sandbox Code Playgroud)

这里只是最简单的存储结构:

use strict;
use warnings;
use constant TIME     => 0;
use constant DISTANCE => 1;

my @data = map { [ split ] } grep { index( $_, '@' ) == -1 } @lines;
Run Code Online (Sandbox Code Playgroud)

然后,您可以按插槽名称处理不同的字段.

foreach my $row ( @data ) {
    printf "At time : %d, distance was %f\n", $row->[TIME], $row->[DISTANCE];
}
Run Code Online (Sandbox Code Playgroud)