Beefy Boxes and Bandwidth Generously Provided by pair Networks
No such thing as a small change
 
PerlMonks  

serial comma function

by Your Mother (Archbishop)
on Apr 15, 2003 at 01:51 UTC ( [id://250449]=CUFP: print w/replies, xml ) Need Help??

I've used this in most CGIs (from a personal ~/lib/Tools.pm) as a way of human formatting missing fields or other list-ish items back to the user. It's a bit obfuscated but I've never needed to change it so I like it better this way.

Update (15 Aug 2004) Template Toolkit version added.

sub serial { join(', ', @_[0..$#_-1]) . (@_>2 ? ',':'' ) . (@_>1 ? (' and ' . $_[-1]) : $_[-1]); }
NB: removed prototype (@) from sub because as Aristotle pointed out it wasn't really doing anything.

sample usage

my @primate = qw( sifaka gibbon tarsier langur ); print "Endangered primates: ", serial(@primate), ".\n";
  Endangered primates: sifaka, gibbon, tarsier, and langur.

Update: Serial comma virtual method with Template Toolkit (same code, different use). Found I missed it when moving to TT2 so discovered how to transplant it.

# in some parent formatting, template processing module use Template; # not actually using it in the code here use Template::Stash; $Template::Stash::LIST_OPS->{ serial } = sub { my @list = @{ +shift || [] }; join(', ', @list[0..$#list-1]) . (@list>2 ? ',':'' ) . (@list>1 ? (' and ' . $list[-1]) : $list[-1]); };

Now in TT code you can do this with lists:

Hey, Joe. Where you going with that [% user.ListOfItems.serial %] in your hand?

Replies are listed 'Best First'.
Re: serial comma function
by rob_au (Abbot) on Apr 15, 2003 at 02:48 UTC
    <comment mode="pedantic">

    My understanding of English grammar is that a comma should not precede an 'and' statement when describing a list - If I am mistaken on this understanding, please feel free to enlighten me. Be that the case however, I would rewrite your function as follows:

    sub serial { join( ', ', @_[ 0..$#_-1 ] ) . ( @_ > 1 ? ' and ' : '' ) . $_[-1] }

     

    perl -le 'print+unpack("N",pack("B32","00000000000000000000001001001011"))'

      This is one of those old raging debates. I used to be in the camp you describe, but came around over time b/c the serial comma is clearer grammatically. It is more flexible too and allows things like, "exotic reptiles, cats and dogs, arachnids, and crustaceans," to read better.

      It also clears up ambiguity that happens with non-serial comma lists, as demonstrated in this excellent example I found on another site: "I'd like to thank my parents, Ayn Rand and God."

      I'd just like to add to Your Mother's fine comments on the subject. The idea of dropping the comma before "and" in lists of more than 2 items was popularized by newspapers motivated by cutting costs to increase profits. Although the professional writers and editors of newspapers have been sources of some fine guidance in the art of writing, they quite simply got this one wrong.

      Some respected producers of style guides have previously adopted this no-comma rule because it came from a respected source (professional writers). Other respected producers of style guides have tried to stradle the fence and say that such a comma is optional but should be used when it makes the meaning clearer. But this latter stance only allows for the removal of ambiguity in one direction, not allowing the absense of the comma to convey any meaning.

      So you really should only drop this comma if you feel that you are saving more in ink/paper/bits than you are losing in power and clarity of expression. For me, the exchange rates among these currencies makes that decision effortless.

      I'd be interested in well-reasoned arguments for the eliding of this comma. The only ones I've heard to date fit in with our most recent poll topic, such as "Appeal to Authority" or "Appeal to Popularity".

Re: serial comma function
by Aristotle (Chancellor) on Apr 15, 2003 at 21:05 UTC
    Nice job, ++. But why the prototype? That one is the same as not specifying any, anyway. You can also get rid of a last smidgen of redundancy in the second ternary.
    sub serial { join(', ', @_[0 .. $#_-1]) . (@_ > 2 ? ',' : '') . (@_ > 1 ? ' and ' : '') . $_[-1]; }
    I think it'd look cleaner with a pop, too.
    sub serial { my $last = pop; join(', ', @_) . (@_ > 1 ? ',' : '') . (@_ > 0 ? ' and ' : '') . $last; }

    Makeshifts last the longest.

      I agree cleaner with pop, but to many ternary operators. :)
      sub serial { my $last = pop; @_ ? join(', ', @_) . " and $last" : $last; }
      update:forgot about that whole, if there are more than two in the list with the commas bit, so neglect the above as it does not do what the original code posted does (as Aristotle's does.)

      -enlil

        I was actually about to reply with something similar myself before I noticed there's three cases to distinguish. FWIW, here's my previous take - which adds a comma even when there's only two elements in the list:
        sub serial { my $last = ''; ($last, $_[-1]) = ($_[-1], 'and ') if @_ > 1; join(', ', @_) . $last; }

        Makeshifts last the longest.

Re: serial comma function
by Aristotle (Chancellor) on Apr 16, 2003 at 00:18 UTC
    A superstraightforward version:
    sub serial { my $last = pop; my $seclast = pop; $seclast .= ',' if @_; join('', map "$_, ", @_) . join(' and ', $seclast || (), $last); }
    Update: added $seclast .= ',' if @_;

    Makeshifts last the longest.

      nice. i'll put an adendum in about the prototype not being needed; or just kill it and put a note in about that instead.
        Yes, nice, except it doesn't work as specified. *grumble* It doesn't add an extra comma for lists of more than two elements. I don't know where I had my eyes (or my brain, for that matter) when I was testing it.

        Makeshifts last the longest.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: CUFP [id://250449]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others imbibing at the Monastery: (4)
As of 2024-04-19 21:55 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found