[11367] in Perl-Users-Digest
Perl-Users Digest, Issue: 4967 Volume: 8
daemon@ATHENA.MIT.EDU (Perl-Users Digest)
Fri Feb 26 11:27:25 1999
Date: Fri, 26 Feb 99 08:20:55 -0800
From: Perl-Users Digest <Perl-Users-Request@ruby.OCE.ORST.EDU>
To: Perl-Users@ruby.OCE.ORST.EDU (Perl-Users Digest)
Perl-Users Digest Fri, 26 Feb 1999 Volume: 8 Number: 4967
Today's topics:
FAQ 4.28: How can I split a [character] delimited strin <perlfaq-suggestions@perl.com>
FAQ 4.29: How do I strip blank space from the beginning <perlfaq-suggestions@perl.com>
Re: FAQ 4.29: How do I strip blank space from the begin <trevor@bunny.demon.co.uk>
Re: FAQ 4.29: How do I strip blank space from the begin <tchrist@mox.perl.com>
Re: FAQ 4.29: How do I strip blank space from the begin <jklein@alerts.co.il>
FAQ 4.30: How do I pad a string with blanks or pad a nu <perlfaq-suggestions@perl.com>
FAQ 4.31: How do I extract selected columns from a stri <perlfaq-suggestions@perl.com>
FAQ 4.32: How do I find the soundex value of a string? <perlfaq-suggestions@perl.com>
FAQ 4.33: How can I expand variables in text strings? <perlfaq-suggestions@perl.com>
FAQ 4.34: What's wrong with always quoting "$vars"? <perlfaq-suggestions@perl.com>
FAQ 4.35: Why don't my E<lt>E<lt>HERE documents work? <perlfaq-suggestions@perl.com>
FAQ 4.36: What is the difference between a list and an <perlfaq-suggestions@perl.com>
Re: FAQ 4.36: What is the difference between a list and (Leo Schalkwyk)
Re: FAQ 4.36: What is the difference between a list and <tchrist@mox.perl.com>
FAQ 4.37: What is the difference between $array[1] and <perlfaq-suggestions@perl.com>
FAQ 4.38: How can I extract just the unique elements of <perlfaq-suggestions@perl.com>
FAQ 4.39: How can I tell whether a list or array contai <perlfaq-suggestions@perl.com>
FAQ 4.40: How do I compute the difference of two arrays <perlfaq-suggestions@perl.com>
FAQ 4.41: How do I test whether two arrays or hashes ar <perlfaq-suggestions@perl.com>
FAQ 4.42: How do I find the first array element for whi <perlfaq-suggestions@perl.com>
FAQ 4.43: How do I handle linked lists? <perlfaq-suggestions@perl.com>
FAQ 4.44: How do I handle circular lists? <perlfaq-suggestions@perl.com>
FAQ 4.45: How do I shuffle an array randomly? <perlfaq-suggestions@perl.com>
Special: Digest Administrivia (Last modified: 12 Dec 98 (Perl-Users-Digest Admin)
----------------------------------------------------------------------
Date: 21 Feb 1999 15:39:11 -0700
From: Tom Christiansen <perlfaq-suggestions@perl.com>
Subject: FAQ 4.28: How can I split a [character] delimited string except when inside [character]? (Comma-separated files)
Message-Id: <36d08b0f@csnews>
(This excerpt from perlfaq4 - Data Manipulation
($Revision: 1.43 $, $Date: 1999/01/26 09:57:23 $)
part of the standard set of documentation included with every
valid Perl distribution, like the one on your system.
See also http://language.perl.com/newdocs/pod/perlfaq4.html
if your negligent system adminstrator has been remiss in his duties.)
How can I split a [character] delimited string except when inside
[character]? (Comma-separated files)
Take the example case of trying to split a string that is comma-
separated into its different fields. (We'll pretend you said comma-
separated, not comma-delimited, which is different and almost never what
you mean.) You can't use `split(/,/)' because you shouldn't split if the
comma is inside quotes. For example, take a data line like this:
SAR001,"","Cimetrix, Inc","Bob Smith","CAM",N,8,1,0,7,"Error, Core Dumped"
Due to the restriction of the quotes, this is a fairly complex problem.
Thankfully, we have Jeffrey Friedl, author of a highly recommended book
on regular expressions, to handle these for us. He suggests (assuming
your string is contained in $text):
@new = ();
push(@new, $+) while $text =~ m{
"([^\"\\]*(?:\\.[^\"\\]*)*)",? # groups the phrase inside the quotes
| ([^,]+),?
| ,
}gx;
push(@new, undef) if substr($text,-1,1) eq ',';
If you want to represent quotation marks inside a quotation-mark-
delimited field, escape them with backslashes (eg, `"like \"this\""'.
Unescaping them is a task addressed earlier in this section.
Alternatively, the Text::ParseWords module (part of the standard perl
distribution) lets you say:
use Text::ParseWords;
@new = quotewords(",", 0, $text);
There's also a Text::CSV module on CPAN.
--
If I allowed "next $label" then I'd also have to allow "goto $label",
and I don't think you really want that... :-) [now works in perl5!]
--Larry Wall in <1991Mar11.230002.27271@jpl-devvax.jpl.nasa.gov>
------------------------------
Date: 21 Feb 1999 16:39:13 -0700
From: Tom Christiansen <perlfaq-suggestions@perl.com>
Subject: FAQ 4.29: How do I strip blank space from the beginning/end of a string?
Message-Id: <36d09921@csnews>
(This excerpt from perlfaq4 - Data Manipulation
($Revision: 1.43 $, $Date: 1999/01/26 09:57:23 $)
part of the standard set of documentation included with every
valid Perl distribution, like the one on your system.
See also http://language.perl.com/newdocs/pod/perlfaq4.html
if your negligent system adminstrator has been remiss in his duties.)
How do I strip blank space from the beginning/end of a string?
Although the simplest approach would seem to be:
$string =~ s/^\s*(.*?)\s*$/$1/;
This is unnecessarily slow, destructive, and fails with embedded
newlines. It is much better faster to do this in two steps:
$string =~ s/^\s+//;
$string =~ s/\s+$//;
Or more nicely written as:
for ($string) {
s/^\s+//;
s/\s+$//;
}
This idiom takes advantage of the `foreach' loop's aliasing behavior to
factor out common code. You can do this on several strings at once, or
arrays, or even the values of a hash if you use a slide:
# trim whitespace in the scalar, the array,
# and all the values in the hash
foreach ($scalar, @array, @hash{keys %hash}) {
s/^\s+//;
s/\s+$//;
}
--
"All things are proceeding rapidly to their contusion." --Larry Wall
------------------------------
Date: Tue, 23 Feb 1999 12:22:48 -0000
From: "Trevor Squires" <trevor@bunny.demon.co.uk>
Subject: Re: FAQ 4.29: How do I strip blank space from the beginning/end of a string?
Message-Id: <919772517.17004.0.nnrp-11.9e9838e3@news.demon.co.uk>
I've been going thru all of the FAQ postings to re-familiarise myself with
perl. Something in this one struck me as odd - see below
Tom Christiansen wrote in message <36d09921@csnews>...
>(This excerpt from perlfaq4 - Data Manipulation
> ($Revision: 1.43 $, $Date: 1999/01/26 09:57:23 $)
>part of the standard set of documentation included with every
<SNIP>
> # trim whitespace in the scalar, the array,
> # and all the values in the hash
> foreach ($scalar, @array, @hash{keys %hash}) {
^^^^^^^^^^^^^^^^^^^^^^^^^^^
a - what does that mean in english? I've never seen curlies used like that.
b - why not just do: foreach ($scalar, @array, values %hash) ?
Thanks loads,
Trevor
------------------------------
Date: 23 Feb 1999 07:04:18 -0700
From: Tom Christiansen <tchrist@mox.perl.com>
Subject: Re: FAQ 4.29: How do I strip blank space from the beginning/end of a string?
Message-Id: <36d2b562@csnews>
[courtesy cc of this posting sent to cited author via email]
In comp.lang.perl.misc, "Trevor Squires" <trevor@bunny.demon.co.uk> writes:
:I've been going thru all of the FAQ postings to re-familiarise myself with
:perl.
Hurray! It's amazing how many people who just haven't read it, or else
haven't read it in forever. I have been getting no end of thank-yous
for doing this. People want to see things in small chunks.
:Something in this one struck me as odd - see below
:> foreach ($scalar, @array, @hash{keys %hash}) {
:a - what does that mean in english? I've never seen curlies used like that.
:b - why not just do: foreach ($scalar, @array, values %hash) ?
>From an ultra-recent updated to perlfunc's entry on values():
Note that you cannot modify the values of a hash this way, because
the returned list is just a copy. You need to use a hash slice for
that, since it's lvaluable in a way that values() is not.
for (values %hash) { s/foo/bar/g } # FAILS!
for (@hash{keys %hash}) { s/foo/bar/g } # ok
--tom
--
"A good messenger expects to get shot." --Larry Wall
------------------------------
Date: Tue, 23 Feb 1999 16:52:48 +0200
From: Yossi Klein <jklein@alerts.co.il>
To: Trevor Squires <trevor@bunny.demon.co.uk>
Subject: Re: FAQ 4.29: How do I strip blank space from the beginning/end of a string?
Message-Id: <Pine.SO4.4.10.9902231642180.2213-100000@cain.alerts.co.il>
When doing a foreach, the index variable 'magically' becomes the variable
that it is currently referring to:
For instance, if $a = 'abc'
and you do
foreach $idx ($a)
{
$idx =~ s/a//;
}
then $a will now be 'bc'. (Obviously, this also works for the default
index variable of the foreach() a.k.a. $_ - I just put in $idx for
clarity).
If you do a foreach (values %abc), then $_ becomes an 'alias' for each
element of the anonymous list returned by values(). The actual elements of
%abc won't be changed.
If, however, you do foreach (@abc{keys %abc}), $_ actually becomes the
value of each element of the hash, and modifying $_ will modify the
elements in %abc.
I hope this makes sense.
Yossi Klein
News Alert Inc.
On Tue, 23 Feb 1999, Trevor Squires wrote:
> I've been going thru all of the FAQ postings to re-familiarise myself with
> perl. Something in this one struck me as odd - see below
>
> Tom Christiansen wrote in message <36d09921@csnews>...
> >(This excerpt from perlfaq4 - Data Manipulation
> > ($Revision: 1.43 $, $Date: 1999/01/26 09:57:23 $)
>
> >part of the standard set of documentation included with every
>
> <SNIP>
>
> > # trim whitespace in the scalar, the array,
> > # and all the values in the hash
> > foreach ($scalar, @array, @hash{keys %hash}) {
>
> ^^^^^^^^^^^^^^^^^^^^^^^^^^^
> a - what does that mean in english? I've never seen curlies used like that.
> b - why not just do: foreach ($scalar, @array, values %hash) ?
>
> Thanks loads,
> Trevor
>
>
>
>
------------------------------
Date: 21 Feb 1999 17:39:15 -0700
From: Tom Christiansen <perlfaq-suggestions@perl.com>
Subject: FAQ 4.30: How do I pad a string with blanks or pad a number with zeroes?
Message-Id: <36d0a733@csnews>
(This excerpt from perlfaq4 - Data Manipulation
($Revision: 1.43 $, $Date: 1999/01/26 09:57:23 $)
part of the standard set of documentation included with every
valid Perl distribution, like the one on your system.
See also http://language.perl.com/newdocs/pod/perlfaq4.html
if your negligent system adminstrator has been remiss in his duties.)
How do I pad a string with blanks or pad a number with zeroes?
(This answer contributed by Uri Guttman)
In the following examples, `$pad_len' is the length to which you wish to
pad the string, `$text' or `$num' contains the string to be padded, and
`$pad_char' contains the padding character. You can use a single
character string constant instead of the `$pad_char' variable if you
know what it is in advance.
The simplest method use the `sprintf' function. It can pad on the left
or right with blanks and on the left with zeroes.
# Left padding with blank:
$padded = sprintf( "%${pad_len}s", $text ) ;
# Right padding with blank:
$padded = sprintf( "%${pad_len}s", $text ) ;
# Left padding with 0:
$padded = sprintf( "%0${pad_len}d", $num ) ;
If you need to pad with a character other than blank or zero you can use
one of the following methods.
These methods generate a pad string with the `x' operator and
concatenate that with the original text.
Left and right padding with any character:
$padded = $pad_char x ( $pad_len - length( $text ) ) . $text ;
$padded = $text . $pad_char x ( $pad_len - length( $text ) ) ;
Or you can left or right pad $text directly:
$text .= $pad_char x ( $pad_len - length( $text ) ) ;
substr( $text, 0, 0 ) = $pad_char x ( $pad_len - length( $text ) ) ;
--
"SPARC" is "CRAPS" backwards --Rob Pike
------------------------------
Date: 21 Feb 1999 18:39:17 -0700
From: Tom Christiansen <perlfaq-suggestions@perl.com>
Subject: FAQ 4.31: How do I extract selected columns from a string?
Message-Id: <36d0b545@csnews>
(This excerpt from perlfaq4 - Data Manipulation
($Revision: 1.43 $, $Date: 1999/01/26 09:57:23 $)
part of the standard set of documentation included with every
valid Perl distribution, like the one on your system.
See also http://language.perl.com/newdocs/pod/perlfaq4.html
if your negligent system adminstrator has been remiss in his duties.)
How do I extract selected columns from a string?
Use substr() or unpack(), both documented in the perlfunc manpage. If
you prefer thinking in terms of columns instead of widths, you can use
this kind of thing:
# determine the unpack format needed to split Linux ps output
# arguments are cut columns
my $fmt = cut2fmt(8, 14, 20, 26, 30, 34, 41, 47, 59, 63, 67, 72);
sub cut2fmt {
my(@positions) = @_;
my $template = '';
my $lastpos = 1;
for my $place (@positions) {
$template .= "A" . ($place - $lastpos) . " ";
$lastpos = $place;
}
$template .= "A*";
return $template;
}
--
X-Windows: The problem for your problem.
--Jamie Zawinski
------------------------------
Date: 21 Feb 1999 19:39:20 -0700
From: Tom Christiansen <perlfaq-suggestions@perl.com>
Subject: FAQ 4.32: How do I find the soundex value of a string?
Message-Id: <36d0c358@csnews>
(This excerpt from perlfaq4 - Data Manipulation
($Revision: 1.43 $, $Date: 1999/01/26 09:57:23 $)
part of the standard set of documentation included with every
valid Perl distribution, like the one on your system.
See also http://language.perl.com/newdocs/pod/perlfaq4.html
if your negligent system adminstrator has been remiss in his duties.)
How do I find the soundex value of a string?
Use the standard Text::Soundex module distributed with perl.
--
if (*name == '+' && len > 1 && name[len-1] != '|') { /* scary */
--Larry Wall, from doio.c in the v5.0 perl distribution
------------------------------
Date: 21 Feb 1999 20:39:22 -0700
From: Tom Christiansen <perlfaq-suggestions@perl.com>
Subject: FAQ 4.33: How can I expand variables in text strings?
Message-Id: <36d0d16a@csnews>
(This excerpt from perlfaq4 - Data Manipulation
($Revision: 1.43 $, $Date: 1999/01/26 09:57:23 $)
part of the standard set of documentation included with every
valid Perl distribution, like the one on your system.
See also http://language.perl.com/newdocs/pod/perlfaq4.html
if your negligent system adminstrator has been remiss in his duties.)
How can I expand variables in text strings?
Let's assume that you have a string like:
$text = 'this has a $foo in it and a $bar';
If those were both global variables, then this would suffice:
$text =~ s/\$(\w+)/${$1}/g; # no /e needed
But since they are probably lexicals, or at least, they could be, you'd
have to do this:
$text =~ s/(\$\w+)/$1/eeg;
die if $@; # needed /ee, not /e
It's probably better in the general case to treat those variables as
entries in some special hash. For example:
%user_defs = (
foo => 23,
bar => 19,
);
$text =~ s/\$(\w+)/$user_defs{$1}/g;
See also ``How do I expand function calls in a string?'' in this section
of the FAQ.
--
Perl has grown from being a very good scripting language into something
like a cross between a universal solvent and an open-ended Mandarin
where new ideograms are invented hourly. --Jeffrey Davis
------------------------------
Date: 21 Feb 1999 21:39:24 -0700
From: Tom Christiansen <perlfaq-suggestions@perl.com>
Subject: FAQ 4.34: What's wrong with always quoting "$vars"?
Message-Id: <36d0df7c@csnews>
(This excerpt from perlfaq4 - Data Manipulation
($Revision: 1.43 $, $Date: 1999/01/26 09:57:23 $)
part of the standard set of documentation included with every
valid Perl distribution, like the one on your system.
See also http://language.perl.com/newdocs/pod/perlfaq4.html
if your negligent system adminstrator has been remiss in his duties.)
What's wrong with always quoting "$vars"?
The problem is that those double-quotes force stringification, coercing
numbers and references into strings, even when you don't want them to
be. Think of it this way: double-quote expansion is used to produce new
strings. If you already have a string, why do you need more?
If you get used to writing odd things like these:
print "$var"; # BAD
$new = "$old"; # BAD
somefunc("$var"); # BAD
You'll be in trouble. Those should (in 99.8% of the cases) be the
simpler and more direct:
print $var;
$new = $old;
somefunc($var);
Otherwise, besides slowing you down, you're going to break code when the
thing in the scalar is actually neither a string nor a number, but a
reference:
func(\@array);
sub func {
my $aref = shift;
my $oref = "$aref"; # WRONG
}
You can also get into subtle problems on those few operations in Perl
that actually do care about the difference between a string and a
number, such as the magical `++' autoincrement operator or the syscall()
function.
Stringification also destroys arrays.
@lines = `command`;
print "@lines"; # WRONG - extra blanks
print @lines; # right
--
It's there as a sop to former Ada programmers. :-)
--Larry Wall regarding 10_000_000 in <11556@jpl-devvax.JPL.NASA.GOV>
------------------------------
Date: 21 Feb 1999 22:39:27 -0700
From: Tom Christiansen <perlfaq-suggestions@perl.com>
Subject: FAQ 4.35: Why don't my E<lt>E<lt>HERE documents work?
Message-Id: <36d0ed8f@csnews>
(This excerpt from perlfaq4 - Data Manipulation
($Revision: 1.43 $, $Date: 1999/01/26 09:57:23 $)
part of the standard set of documentation included with every
valid Perl distribution, like the one on your system.
See also http://language.perl.com/newdocs/pod/perlfaq4.html
if your negligent system adminstrator has been remiss in his duties.)
Why don't my <<HERE documents work?
Check for these three things:
1. There must be no space after the << part.
2. There (probably) should be a semicolon at the end.
3. You can't (easily) have any space in front of the tag.
If you want to indent the text in the here document, you can do this:
# all in one
($VAR = <<HERE_TARGET) =~ s/^\s+//gm;
your text
goes here
HERE_TARGET
But the HERE_TARGET must still be flush against the margin. If you want
that indented also, you'll have to quote in the indentation.
($quote = <<' FINIS') =~ s/^\s+//gm;
...we will have peace, when you and all your works have
perished--and the works of your dark master to whom you
would deliver us. You are a liar, Saruman, and a corrupter
of men's hearts. --Theoden in /usr/src/perl/taint.c
FINIS
$quote =~ s/\s*--/\n--/;
A nice general-purpose fixer-upper function for indented here documents
follows. It expects to be called with a here document as its argument.
It looks to see whether each line begins with a common substring, and if
so, strips that off. Otherwise, it takes the amount of leading white
space found on the first line and removes that much off each subsequent
line.
sub fix {
local $_ = shift;
my ($white, $leader); # common white space and common leading string
if (/^\s*(?:([^\w\s]+)(\s*).*\n)(?:\s*\1\2?.*\n)+$/) {
($white, $leader) = ($2, quotemeta($1));
} else {
($white, $leader) = (/^(\s+)/, '');
}
s/^\s*?$leader(?:$white)?//gm;
return $_;
}
This works with leading special strings, dynamically determined:
$remember_the_main = fix<<' MAIN_INTERPRETER_LOOP';
@@@ int
@@@ runops() {
@@@ SAVEI32(runlevel);
@@@ runlevel++;
@@@ while ( op = (*op->op_ppaddr)() ) ;
@@@ TAINT_NOT;
@@@ return 0;
@@@ }
MAIN_INTERPRETER_LOOP
Or with a fixed amount of leading white space, with remaining
indentation correctly preserved:
$poem = fix<<EVER_ON_AND_ON;
Now far ahead the Road has gone,
And I must follow, if I can,
Pursuing it with eager feet,
Until it joins some larger way
Where many paths and errands meet.
And whither then? I cannot say.
--Bilbo in /usr/src/perl/pp_ctl.c
EVER_ON_AND_ON
--
"You need to go and find someone to teach you the rudiments of irrational
discourse." --Larry Wall
------------------------------
Date: 21 Feb 1999 23:39:29 -0700
From: Tom Christiansen <perlfaq-suggestions@perl.com>
Subject: FAQ 4.36: What is the difference between a list and an array?
Message-Id: <36d0fba1@csnews>
(This excerpt from perlfaq4 - Data Manipulation
($Revision: 1.43 $, $Date: 1999/01/26 09:57:23 $)
part of the standard set of documentation included with every
valid Perl distribution, like the one on your system.
See also http://language.perl.com/newdocs/pod/perlfaq4.html
if your negligent system adminstrator has been remiss in his duties.)
What is the difference between a list and an array?
An array has a changeable length. A list does not. An array is something
you can push or pop, while a list is a set of values. Some people make
the distinction that a list is a value while an array is a variable.
Subroutines are passed and return lists, you put things into list
context, you initialize arrays with lists, and you foreach() across a
list. `@' variables are arrays, anonymous arrays are arrays, arrays in
scalar context behave like the number of elements in them, subroutines
access their arguments through the array `@_', push/pop/shift only work
on arrays.
As a side note, there's no such thing as a list in scalar context. When
you say
$scalar = (2, 5, 7, 9);
you're using the comma operator in scalar context, so it evaluates the
left hand side, then evaluates and returns the left hand side. This
causes the last value to be returned: 9.
--
"To claim any more than that is to invite a religious war, which I ain't.
Go thou and don't likewise."
--Larry Wall
------------------------------
Date: 22 Feb 1999 18:13:51 GMT
From: schalkwy@minnie.RZ-Berlin.MPG.DE (Leo Schalkwyk)
Subject: Re: FAQ 4.36: What is the difference between a list and an array?
Message-Id: <7as6ov$oga$1@fu-berlin.de>
Tom Christiansen (perlfaq-suggestions@perl.com) wrote:
: (This excerpt from perlfaq4 - Data Manipulation
<snip>
: you're using the comma operator in scalar context, so it evaluates the
: left hand side, then evaluates and returns the left hand side. This
^^^^^ ^^^^^
um, right?
: causes the last value to be returned: 9.
: --
: "To claim any more than that is to invite a religious war, which I ain't.
: Go thou and don't likewise."
: --Larry Wall
--
------------------------------
Date: 22 Feb 1999 11:33:28 -0700
From: Tom Christiansen <tchrist@mox.perl.com>
Subject: Re: FAQ 4.36: What is the difference between a list and an array?
Message-Id: <36d1a2f8@csnews>
[courtesy cc of this posting sent to cited author via email]
In comp.lang.perl.misc, schalkwy@minnie.RZ-Berlin.MPG.DE (Leo Schalkwyk) writes:
:Tom Christiansen (perlfaq-suggestions@perl.com) wrote:
:: you're using the comma operator in scalar context, so it evaluates the
:: left hand side, then evaluates and returns the left hand side. This
: ^^^^^ ^^^^^
: um, right?
right.
--tom
--
Unix is defined by whatever is running on Dennis Ritchie's machine.
------------------------------
Date: 22 Feb 1999 00:39:31 -0700
From: Tom Christiansen <perlfaq-suggestions@perl.com>
Subject: FAQ 4.37: What is the difference between $array[1] and @array[1]?
Message-Id: <36d109b3@csnews>
(This excerpt from perlfaq4 - Data Manipulation
($Revision: 1.43 $, $Date: 1999/01/26 09:57:23 $)
part of the standard set of documentation included with every
valid Perl distribution, like the one on your system.
See also http://language.perl.com/newdocs/pod/perlfaq4.html
if your negligent system adminstrator has been remiss in his duties.)
What is the difference between $array[1] and @array[1]?
The former is a scalar value, the latter an array slice, which makes it
a list with one (scalar) value. You should use $ when you want a scalar
value (most of the time) and @ when you want a list with one scalar
value in it (very, very rarely; nearly never, in fact).
Sometimes it doesn't make a difference, but sometimes it does. For
example, compare:
$good[0] = `some program that outputs several lines`;
with
@bad[0] = `same program that outputs several lines`;
The -w flag will warn you about these matters.
--
If you can stick your finger in it, you can hang from it. --Andrew Hume
------------------------------
Date: 22 Feb 1999 01:39:34 -0700
From: Tom Christiansen <perlfaq-suggestions@perl.com>
Subject: FAQ 4.38: How can I extract just the unique elements of an array?
Message-Id: <36d117c6@csnews>
(This excerpt from perlfaq4 - Data Manipulation
($Revision: 1.43 $, $Date: 1999/01/26 09:57:23 $)
part of the standard set of documentation included with every
valid Perl distribution, like the one on your system.
See also http://language.perl.com/newdocs/pod/perlfaq4.html
if your negligent system adminstrator has been remiss in his duties.)
How can I extract just the unique elements of an array?
There are several possible ways, depending on whether the array is
ordered and whether you wish to preserve the ordering.
a) If @in is sorted, and you want @out to be sorted:
(this assumes all true values in the array)
$prev = 'nonesuch';
@out = grep($_ ne $prev && ($prev = $_), @in);
This is nice in that it doesn't use much extra memory, simulating
uniq(1)'s behavior of removing only adjacent duplicates. It's less
nice in that it won't work with false values like undef, 0, or "";
"0 but true" is ok, though.
b) If you don't know whether @in is sorted:
undef %saw;
@out = grep(!$saw{$_}++, @in);
c) Like (b), but @in contains only small integers:
@out = grep(!$saw[$_]++, @in);
d) A way to do (b) without any loops or greps:
undef %saw;
@saw{@in} = ();
@out = sort keys %saw; # remove sort if undesired
e) Like (d), but @in contains only small positive integers:
undef @ary;
@ary[@in] = @in;
@out = @ary;
But perhaps you should have been using a hash all along, eh?
--
That means I'll have to use $ans to suppress newlines now.
Life is ridiculous.
--Larry Wall in Configure from the perl distribution
------------------------------
Date: 22 Feb 1999 02:39:36 -0700
From: Tom Christiansen <perlfaq-suggestions@perl.com>
Subject: FAQ 4.39: How can I tell whether a list or array contains a certain element?
Message-Id: <36d125d8@csnews>
(This excerpt from perlfaq4 - Data Manipulation
($Revision: 1.43 $, $Date: 1999/01/26 09:57:23 $)
part of the standard set of documentation included with every
valid Perl distribution, like the one on your system.
See also http://language.perl.com/newdocs/pod/perlfaq4.html
if your negligent system adminstrator has been remiss in his duties.)
How can I tell whether a list or array contains a certain element?
Hearing the word "in" is an *in*dication that you probably should have
used a hash, not a list or array, to store your data. Hashes are
designed to answer this question quickly and efficiently. Arrays aren't.
That being said, there are several ways to approach this. If you are
going to make this query many times over arbitrary string values, the
fastest way is probably to invert the original array and keep an
associative array lying about whose keys are the first array's values.
@blues = qw/azure cerulean teal turquoise lapis-lazuli/;
undef %is_blue;
for (@blues) { $is_blue{$_} = 1 }
Now you can check whether $is_blue{$some_color}. It might have been a
good idea to keep the blues all in a hash in the first place.
If the values are all small integers, you could use a simple indexed
array. This kind of an array will take up less space:
@primes = (2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31);
undef @is_tiny_prime;
for (@primes) { $is_tiny_prime[$_] = 1; }
Now you check whether $is_tiny_prime[$some_number].
If the values in question are integers instead of strings, you can save
quite a lot of space by using bit strings instead:
@articles = ( 1..10, 150..2000, 2017 );
undef $read;
for (@articles) { vec($read,$_,1) = 1 }
Now check whether `vec($read,$n,1)' is true for some `$n'.
Please do not use
$is_there = grep $_ eq $whatever, @array;
or worse yet
$is_there = grep /$whatever/, @array;
These are slow (checks every element even if the first matches),
inefficient (same reason), and potentially buggy (what if there are
regexp characters in $whatever?). If you're only testing once, then use:
$is_there = 0;
foreach $elt (@array) {
if ($elt eq $elt_to_find) {
$is_there = 1;
last;
}
}
if ($is_there) { ... }
--
The X server has to be the biggest program I've ever seen that doesn't
do anything for you. --Ken Thompson
------------------------------
Date: 22 Feb 1999 03:39:44 -0700
From: Tom Christiansen <perlfaq-suggestions@perl.com>
Subject: FAQ 4.40: How do I compute the difference of two arrays? How do I compute the intersection of two arrays?
Message-Id: <36d133f0@csnews>
(This excerpt from perlfaq4 - Data Manipulation
($Revision: 1.43 $, $Date: 1999/01/26 09:57:23 $)
part of the standard set of documentation included with every
valid Perl distribution, like the one on your system.
See also http://language.perl.com/newdocs/pod/perlfaq4.html
if your negligent system adminstrator has been remiss in his duties.)
How do I compute the difference of two arrays? How do I compute the intersection of two arrays?
Use a hash. Here's code to do both and more. It assumes that each
element is unique in a given array:
@union = @intersection = @difference = ();
%count = ();
foreach $element (@array1, @array2) { $count{$element}++ }
foreach $element (keys %count) {
push @union, $element;
push @{ $count{$element} > 1 ? \@intersection : \@difference }, $element;
}
--
MAGIC* xmg_magic; /* linked list of magicalness */
--Larry Wall, from sv.h in the v5.0 perl distribution
------------------------------
Date: 22 Feb 1999 04:39:53 -0700
From: Tom Christiansen <perlfaq-suggestions@perl.com>
Subject: FAQ 4.41: How do I test whether two arrays or hashes are equal?
Message-Id: <36d14209@csnews>
(This excerpt from perlfaq4 - Data Manipulation
($Revision: 1.43 $, $Date: 1999/01/26 09:57:23 $)
part of the standard set of documentation included with every
valid Perl distribution, like the one on your system.
See also http://language.perl.com/newdocs/pod/perlfaq4.html
if your negligent system adminstrator has been remiss in his duties.)
How do I test whether two arrays or hashes are equal?
The following code works for single-level arrays. It uses a stringwise
comparison, and does not distinguish defined versus undefined empty
strings. Modify if you have other needs.
$are_equal = compare_arrays(\@frogs, \@toads);
sub compare_arrays {
my ($first, $second) = @_;
local $^W = 0; # silence spurious -w undef complaints
return 0 unless @$first == @$second;
for (my $i = 0; $i < @$first; $i++) {
return 0 if $first->[$i] ne $second->[$i];
}
return 1;
}
For multilevel structures, you may wish to use an approach more like
this one. It uses the CPAN module FreezeThaw:
use FreezeThaw qw(cmpStr);
@a = @b = ( "this", "that", [ "more", "stuff" ] );
printf "a and b contain %s arrays\n",
cmpStr(\@a, \@b) == 0
? "the same"
: "different";
This approach also works for comparing hashes. Here we'll demonstrate
two different answers:
use FreezeThaw qw(cmpStr cmpStrHard);
%a = %b = ( "this" => "that", "extra" => [ "more", "stuff" ] );
$a{EXTRA} = \%b;
$b{EXTRA} = \%a;
printf "a and b contain %s hashes\n",
cmpStr(\%a, \%b) == 0 ? "the same" : "different";
printf "a and b contain %s hashes\n",
cmpStrHard(\%a, \%b) == 0 ? "the same" : "different";
The first reports that both those the hashes contain the same data,
while the second reports that they do not. Which you prefer is left as
an exercise to the reader.
--
Remember why the good Lord made your eyes -- Pla-gi-a-rize! --Tom Lehrer
------------------------------
Date: 22 Feb 1999 05:40:01 -0700
From: Tom Christiansen <perlfaq-suggestions@perl.com>
Subject: FAQ 4.42: How do I find the first array element for which a condition is true?
Message-Id: <36d15021@csnews>
(This excerpt from perlfaq4 - Data Manipulation
($Revision: 1.43 $, $Date: 1999/01/26 09:57:23 $)
part of the standard set of documentation included with every
valid Perl distribution, like the one on your system.
See also http://language.perl.com/newdocs/pod/perlfaq4.html
if your negligent system adminstrator has been remiss in his duties.)
How do I find the first array element for which a condition is true?
You can use this if you care about the index:
for ($i= 0; $i < @array; $i++) {
if ($array[$i] eq "Waldo") {
$found_index = $i;
last;
}
}
Now `$found_index' has what you want.
--
"'My country right or wrong' is like saying, 'My mother drunk or sober.'"
- G. K. Chesterton
------------------------------
Date: 22 Feb 1999 06:40:35 -0700
From: Tom Christiansen <perlfaq-suggestions@perl.com>
Subject: FAQ 4.43: How do I handle linked lists?
Message-Id: <36d15e53@csnews>
(This excerpt from perlfaq4 - Data Manipulation
($Revision: 1.43 $, $Date: 1999/01/26 09:57:23 $)
part of the standard set of documentation included with every
valid Perl distribution, like the one on your system.
See also http://language.perl.com/newdocs/pod/perlfaq4.html
if your negligent system adminstrator has been remiss in his duties.)
How do I handle linked lists?
In general, you usually don't need a linked list in Perl, since with
regular arrays, you can push and pop or shift and unshift at either end,
or you can use splice to add and/or remove arbitrary number of elements
at arbitrary points. Both pop and shift are both O(1) operations on
perl's dynamic arrays. In the absence of shifts and pops, push in
general needs to reallocate on the order every log(N) times, and unshift
will need to copy pointers each time.
If you really, really wanted, you could use structures as described in
the perldsc manpage or the perltoot manpage and do just what the
algorithm book tells you to do. For example, imagine a list node like
this:
$node = {
VALUE => 42,
LINK => undef,
};
You could walk the list this way:
print "List: ";
for ($node = $head; $node; $node = $node->{LINK}) {
print $node->{VALUE}, " ";
}
print "\n";
You could grow the list this way:
my ($head, $tail);
$tail = append($head, 1); # grow a new head
for $value ( 2 .. 10 ) {
$tail = append($tail, $value);
}
sub append {
my($list, $value) = @_;
my $node = { VALUE => $value };
if ($list) {
$node->{LINK} = $list->{LINK};
$list->{LINK} = $node;
} else {
$_[0] = $node; # replace caller's version
}
return $node;
}
But again, Perl's built-in are virtually always good enough.
--
I already have too much problem with people thinking the efficiency of
a perl construct is related to its length. On the other hand, I'm
perfectly capable of changing my mind next week... :-) --lwall
------------------------------
Date: 22 Feb 1999 07:33:26 -0700
From: Tom Christiansen <perlfaq-suggestions@perl.com>
Subject: FAQ 4.44: How do I handle circular lists?
Message-Id: <36d16ab6@csnews>
(This excerpt from perlfaq4 - Data Manipulation
($Revision: 1.43 $, $Date: 1999/01/26 09:57:23 $)
part of the standard set of documentation included with every
valid Perl distribution, like the one on your system.
See also http://language.perl.com/newdocs/pod/perlfaq4.html
if your negligent system adminstrator has been remiss in his duties.)
How do I handle circular lists?
Circular lists could be handled in the traditional fashion with linked
lists, or you could just do something like this with an array:
unshift(@array, pop(@array)); # the last shall be first
push(@array, shift(@array)); # and vice versa
--
Emacs is a fine programming language, but I still prefer perl.
------------------------------
Date: 22 Feb 1999 08:33:36 -0700
From: Tom Christiansen <perlfaq-suggestions@perl.com>
Subject: FAQ 4.45: How do I shuffle an array randomly?
Message-Id: <36d178d0@csnews>
(This excerpt from perlfaq4 - Data Manipulation
($Revision: 1.43 $, $Date: 1999/01/26 09:57:23 $)
part of the standard set of documentation included with every
valid Perl distribution, like the one on your system.
See also http://language.perl.com/newdocs/pod/perlfaq4.html
if your negligent system adminstrator has been remiss in his duties.)
How do I shuffle an array randomly?
Use this:
# fisher_yates_shuffle( \@array ) :
# generate a random permutation of @array in place
sub fisher_yates_shuffle {
my $array = shift;
my $i;
for ($i = @$array; --$i; ) {
my $j = int rand ($i+1);
next if $i == $j;
@$array[$i,$j] = @$array[$j,$i];
}
}
fisher_yates_shuffle( \@array ); # permutes @array in place
You've probably seen shuffling algorithms that works using splice,
randomly picking another element to swap the current element with:
srand;
@new = ();
@old = 1 .. 10; # just a demo
while (@old) {
push(@new, splice(@old, rand @old, 1));
}
This is bad because splice is already O(N), and since you do it N times,
you just invented a quadratic algorithm; that is, O(N**2). This does not
scale, although Perl is so efficient that you probably won't notice this
until you have rather largish arrays.
--
Perl programming is an *empirical* science!
--Larry Wall in <10226@jpl-devvax.JPL.NASA.GOV>
------------------------------
Date: 12 Dec 98 21:33:47 GMT (Last modified)
From: Perl-Request@ruby.oce.orst.edu (Perl-Users-Digest Admin)
Subject: Special: Digest Administrivia (Last modified: 12 Dec 98)
Message-Id: <null>
Administrivia:
Well, after 6 months, here's the answer to the quiz: what do we do about
comp.lang.perl.moderated. Answer: nothing.
]From: Russ Allbery <rra@stanford.edu>
]Date: 21 Sep 1998 19:53:43 -0700
]Subject: comp.lang.perl.moderated available via e-mail
]
]It is possible to subscribe to comp.lang.perl.moderated as a mailing list.
]To do so, send mail to majordomo@eyrie.org with "subscribe clpm" in the
]body. Majordomo will then send you instructions on how to confirm your
]subscription. This is provided as a general service for those people who
]cannot receive the newsgroup for whatever reason or who just prefer to
]receive messages via e-mail.
The Perl-Users Digest is a retransmission of the USENET newsgroup
comp.lang.perl.misc. For subscription or unsubscription requests, send
the single line:
subscribe perl-users
or:
unsubscribe perl-users
to almanac@ruby.oce.orst.edu.
To submit articles to comp.lang.perl.misc (and this Digest), send your
article to perl-users@ruby.oce.orst.edu.
To submit articles to comp.lang.perl.announce, send your article to
clpa@perl.com.
To request back copies (available for a week or so), send your request
to almanac@ruby.oce.orst.edu with the command "send perl-users x.y",
where x is the volume number and y is the issue number.
The Meta-FAQ, an article containing information about the FAQ, is
available by requesting "send perl-users meta-faq". The real FAQ, as it
appeared last in the newsgroup, can be retrieved with the request "send
perl-users FAQ". Due to their sizes, neither the Meta-FAQ nor the FAQ
are included in the digest.
The "mini-FAQ", which is an updated version of the Meta-FAQ, is
available by requesting "send perl-users mini-faq". It appears twice
weekly in the group, but is not distributed in the digest.
For other requests pertaining to the digest, send mail to
perl-users-request@ruby.oce.orst.edu. Do not waste your time or mine
sending perl questions to the -request address, I don't have time to
answer them even if I did know the answer.
------------------------------
End of Perl-Users Digest V8 Issue 4967
**************************************