nidhi has asked for the wisdom of the Perl Monks concerning the following question:

Hi all wisemen
I have an array called @one :
vlan 107 vlan 121 vlan 122,127,129,137
I need to store the elements in rather a comma free manner. The ouput should be instead :
vlan 107 vlan 121 vlan 122 vlan 127 vlan 129 vlan 137
My code can find which element in the array has the comma separated values of vlan. But am not sure how to replace comma with the term vlan.
foreach my $element (@one) { if ($element =~ m/^vlan \d*,\d*/g) { print"$element"; } }
Plz. help!

Replies are listed 'Best First'.
Re: replace separator from array elements
by dwm042 (Priest) on Sep 12, 2007 at 20:08 UTC
    Don't bother replacing the "," with a vlan. Since the text is repetitive, and can be inferred by context, just store the numbers, as so:

    #!/usr/bin/perl use warnings; use strict; my @vlans = (); while(<DATA>) { chomp; s/vlan //i; my @data = split/\,/, $_; foreach my $dat (@data) { push @vlans, $dat; } } for(@vlans) { print "vlan ", $_, "\n"; } __DATA__ vlan 107 vlan 121 vlan 122,127,129,137
    The output is:

    C:\Code>perl vlanlist.pl vlan 107 vlan 121 vlan 122 vlan 127 vlan 129 vlan 137
Re: replace separator from array elements
by artist (Parson) on Sep 12, 2007 at 20:27 UTC
    Here is more 'generic' solution.
    while(<DATA>){ my ($text,$values) = split ; print "$text $_\n" for split /\,/,$values; } __DATA__ vlan 107 vlan 121 vlan 122,127,129,137 hello 678,123,456
    --Artist
Re: replace separator from array elements
by pemungkah (Priest) on Sep 12, 2007 at 21:01 UTC
    EDIT: added the third possibility to the benchmark (null out the 'vlan ' and then split)

    RE-EDIT: grumble grumble markup grumble

    Captures and the /g flag will help here. (Rewritten slightly to allow me to test the code easily.)

    #!/opt/local/bin/perl use strict; use warnings; open my $vlan_in, '<', shift @ARGV; my @vlans = <$vlan_in>; foreach my $line (@vlans) { chomp $line; my @items = ($line =~ /( # capture: \d # digit characters + # one or more in a row )/gx ); # as many as you can find foreach my $item (@items) { next unless defined $item; $item =~ s/,//; print "vlan $item\n"; } }
    The regex is /x'ed for tutorial purposes; you'd almost certainly write it as /(\d+)/g in your program. Since we're using \d+, we'll match the longest possible string of digits in each case. Alternatively, we could use split():
    #!/opt/local/bin/perl use strict; use warnings; open my $vlan_in, '<', shift @ARGV; my @vlans = <$vlan_in>; foreach my $line (@vlans) { chomp $line; # Separate the 'vlan' from the list (and throw it away). my (undef, $vlans) = split /\s+/, $line; # Break up the list into items. my @items = split /,/, $vlans; # Print your new output. foreach my $item (@items) { next unless defined $item; $item =~ s/,//; print "vlan $item\n"; } }
    Timing this:
    use Benchmark qw(:all); my @lines = split /\n/, <<EOF; vlan 107 vlan 121 vlan 122,127,129,137 vlan EOF pop @lines; cmpthese( 500_000, { 'split-split' => sub { my @copy = @lines; foreach my $line (@copy) { my (undef, $vlans) = split /\s+/, $line; my @items = split /,/, $vlans; } }, '/g' => sub { my @copy = @lines; foreach my $line (@copy) { my @items = ($line =~ /(\d+)/g); } }, 'sub-split' => sub { my @copy = @lines; foreach my $line (@copy) { s/vlan //; my @items = split /,/, $line; } }, } );
    shows that substitute then split is fastest. 100 thousand iterations:
    Rate split-split /g sub-split split-split 104167/s -- -8% -22% /g 113636/s 9% -- -15% sub-split 133333/s 28% 17% --
    500 thousand:
    Rate split-split /g sub-split split-split 102459/s -- -11% -26% /g 115741/s 13% -- -16% sub-split 138504/s 35% 20% --
    1 million:
    Rate split-split /g sub-split split-split 100503/s -- -12% -28% /g 114286/s 14% -- -18% sub-split 138889/s 38% 22% --
    5 million:
    Rate split-split /g sub-split split-split 102480/s -- -10% -24% /g 114495/s 12% -- -15% sub-split 134590/s 31% 18% --
    And that's all I feel like running. Obviously sub-split keeps getting better as the number of iterations increase; I think that's because the sub allows the string to be "shrunk" in-place without allocating any more memory. However, it starts falling off again at 5 million iterations; someone with more time than me might want to investigate more iterations.

    Basically, substitute out the stuff you don't need then split is fastest.

    Re: replace separator from array elements
    by dsheroh (Monsignor) on Sep 12, 2007 at 20:08 UTC
      So something like
      #!/usr/bin/perl use strict; use warnings; my @one = ('vlan 107', 'vlan 121', 'vlan 122,127,129,137'); foreach my $element (@one) { my @two = split ',', $element; print join "\nvlan ", @two; print "\n"; }
      ?

      This produces:

      vlan 107 vlan 121 vlan 122 vlan 127 vlan 129 vlan 137
    Re: replace separator from array elements
    by andreas1234567 (Vicar) on Sep 12, 2007 at 20:59 UTC
      TIMTOWTDI:
      use strict; use warnings; my @one = ('vlan 107', 'vlan 121', 'vlan 122,127,129,137'); my @two = map { s/[^\d,]//g; split(q{,}, $_); } @one; print "vlan $_\n" for @two; __END__ $ perl 638661.pl vlan 107 vlan 121 vlan 122 vlan 127 vlan 129 vlan 137
      --
      Andreas