Marc Adler
Marc Adler

Reputation: 534

Adding an "and" before the last element in a comma-interpolated array in Perl

I want to create a subroutine that adds commas to elements and adds an "and" before the last element, e.g., so that "12345" becomes "1, 2, 3, 4, and 5". I know how to add the commas, but the problem is the result I get is "1, 2, 3, 4, and 5," and I don't know how to get rid of the last comma.

sub commas {
  my @with_commas;
  foreach (@_) {
    push (@with_commas, ($_, ", ")); #up to here it's fine
    }
    splice @with_commas, -2, 1, ("and ", $_[-1]);
    @with_commas;
  }

As you can probably tell, I'm trying to delete the last element in the new array (@with_commas), since it has the comma appended, and add in the last element in the old array (@_, passed to the sub routine from the main program, with no added comma).

When I run this, the result is, e.g., "1, 2, 3, 4, and 5," -- with the comma at the end. Where is that comma coming from? Only @with_commas was supposed to get the commas.

Any help is appreciated.

Upvotes: 4

Views: 1311

Answers (7)

Meehatpa
Meehatpa

Reputation: 349

Small hint

for( 1 .. 10 ) {
     print ;
     $_ == 10 ? print '' : ($_ != 9 ? print ', ' : print ' and ');
}

Upvotes: 0

Mark Stosberg
Mark Stosberg

Reputation: 13411

There is a CPAN module for this, Lingua::Conjunction. I use it myself, and recommend it over rolling your own solution. The usage syntax is very simple:

conjunction(@list);

Upvotes: 3

perreal
perreal

Reputation: 98088

#!/usr/bin/perl

use warnings;
use strict;

sub commas {
  return ""    if @_ == 0;
  return $_[0] if @_ == 1;
  my $last = pop @_; 
  my $rest = join (", ", @_);
  return $rest.", and ".$last;
}

my @a = (1,2,3,4,5);
print commas(@a), "\n";

Upvotes: 2

DVK
DVK

Reputation: 129489

Just in the spirit of TIMTOWTDI (though, frankly, @perreal's answer is better as far as readability):

sub commas {
    my $last_index = $#_;
    my @with_commas = map { (($_==$last_index) ? "and " : "") . $_[$_] }
                          0 .. $last_index;
    print join("," @with_commas)
}

This is somewhat similar to Alan's answer (more convoluted/complicated), but the benefit compared to that is that it would work if you need to add "and " to any OTHER element than the last one; Alan's only works when you know the exact offset (e.g. last element)

Upvotes: 1

brian d foy
brian d foy

Reputation: 132896

Add the commas then add the "and ":

use v5.10;

my $string = join ', ', 1 .. 5;

substr 
    $string, 
    rindex( $string, ', ' ) + 2,
    0,
    'and '
    ;

say $string;

So, work that in as the case when you have more than two elements:

use v5.10;

my @array = 1..5;
my $string = do {
    if( @array == 1 ) {
        @array[0];
        }
    elsif( @array == 2 ) {
        join ' and ', @array
        }
    elsif( @array > 2 ) {   
        my $string = join ', ', @array;

        my $commas = $string =~ tr/,//;

        substr 
            $string, 
            rindex( $string, ', ' ) + 2,
            0,
            'and '
            ;

        $string;
        }
    };      

say $string;

Upvotes: 1

ikegami
ikegami

Reputation: 386501

sub format_list {
   return "" if !@_;
   my $last = pop(@_);
   return $last if !@_;
   return join(', ', @_) . " and " . $last;
}

print format_list(@list), "\n";

This also handles lists with only one element, unlike most of the other answers.

Upvotes: 7

Alan Haggai Alavi
Alan Haggai Alavi

Reputation: 74262

You could use join and modify the last element to include an and:

my @list = 1 .. 5;
$list[-1] = "and $list[-1]" if $#list;
print join ', ', @list;

Upvotes: 3

Related Questions