Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Perfecting my Perl

4 views
Skip to first unread message

Gregory Toomey

unread,
Nov 7, 2002, 5:47:00 AM11/7/02
to
I'm helping a relative with some word puzzles but the solution I've come up
with is rather ugly.

Problem:
Make as many words as possible with the letters a,a,c,c,e,i,n,t,v; each
word must contain the letter c.

My solution:
Using the English language word list at www.wordlist.sourceforge.net/ ,
I've come up with the following:

while(<>) {
if (/^[aceintv]*$/ && /c/) {
my %hash;
foreach (split //) {$hash{$_}++};
print "$_" if $hash{v}<=1 && $hash{c}<=2 &&
$hash{c}>=1 && $hash{i}<=1 && $hash{n}<=1 && $hash{t}<=1 && $hash{e}<=1;
}
}

Does somebody have a more elegant solution?

gtoomey

Julia deSilva

unread,
Nov 7, 2002, 7:51:24 AM11/7/02
to
> Does somebody have a more elegant solution?
>
> gtoomey

Try : "Get a Life !"


Tassilo v. Parseval

unread,
Nov 7, 2002, 8:29:39 AM11/7/02
to
Also sprach Julia deSilva:

> Try : "Get a Life !"

Try my killfile.

Tassilo
--
$_=q!",}])(tsuJ[{@"tnirp}3..0}_$;//::niam/s~=)]3[))_$-3(rellac(=_$({
pam{rekcahbus;})(rekcah{lrePbus;})(lreP{rehtonabus;})(rehtona{tsuJbus!;
$_=reverse;s/sub/(reverse"bus").chr(32)/xge;tr~\n~~d;eval;

Bernard El-Hagin

unread,
Nov 7, 2002, 8:36:54 AM11/7/02
to
In article <xjty9.34449$xF....@news-binary.blueyonder.co.uk>, Julia


Why? The OP is just trying to learn. What's wrong with that?


Anyhow, I have a nice, cozy place for you in my killfile.


Cheers,
Bernard
--
echo 42|perl -pe '$#="Just another Perl hacker,"'

Jürgen Exner

unread,
Nov 7, 2002, 9:05:56 AM11/7/02
to

Not sure which part you are trying to solve in your code snippet:
- creating all the permutation of the characters
- comparing them with the list of English words.

If it's about the permutations then you may want to check out "perldoc -q
permute" for some ideas.

jue


Tad McClellan

unread,
Nov 7, 2002, 10:00:21 AM11/7/02
to
Gregory Toomey <nob...@noplace.com> wrote:

> Problem:
> Make as many words as possible with the letters a,a,c,c,e,i,n,t,v; each
> word must contain the letter c.

> while(<>) {
> if (/^[aceintv]*$/ && /c/) {
> my %hash;
> foreach (split //) {$hash{$_}++};
> print "$_" if $hash{v}<=1 && $hash{c}<=2 &&

^ ^
^ ^
Those quotes don't do anything (useful), so they should not be there.


> $hash{c}>=1 && $hash{i}<=1 && $hash{n}<=1 && $hash{t}<=1 && $hash{e}<=1;
> }
> }


Your code does not check for "a" characters...


> Does somebody have a more elegant solution?


This one seems to me to be easier to read and understand:


----------------------------------
while(<>) {
next unless /^[aceintv]*c[aceintv]*$/; # has disallowed character

my $word = $_;
chomp;
foreach my $ch (qw/a a c c e i n t v/) { # remove allowed characters
s/$ch//;
}
print $word unless length; # matched if no chars are left
}
----------------------------------


--
Tad McClellan SGML consulting
ta...@augustmail.com Perl programming
Fort Worth, Texas

Tassilo v. Parseval

unread,
Nov 7, 2002, 11:00:36 AM11/7/02
to
The following posted on request sent in a personal mail from Cameron
Dorey (her newsservice appears to be down):

Gregory Toomey wrote:

>
> My solution:
> Using the English language word list at www.wordlist.sourceforge.net/ ,


Is this the right URL? My computer cannot find it, and it looks like a good
site to test some things I'm doing.

Oh, to your question. If it works, it's elegant. TIMTOWTDI, and, to a first
approximation (okay, within an order of magnitude), they're all equally elegant.

Thanks,

Cameron

--
Cameron Dorey
Associate Professor of Chemistry
University of Central Arkansas
Phone: 501-450-5938
came...@mail.uca.edu

nob...@mail.com

unread,
Nov 7, 2002, 12:57:00 PM11/7/02
to
"Gregory Toomey" <nob...@noplace.com> wrote in message news:<01c2864c$6cb47f00$88498a90@gmtoomey>...

> Subject: Perfecting my Perl

The subject line should have contained the phase "perl golf".

> Problem:
> Make as many words as possible with the letters a,a,c,c,e,i,n,t,v; each
> word must contain the letter c.

> I've come up with the following:


>
> while(<>) {
> if (/^[aceintv]*$/ && /c/) {
> my %hash;
> foreach (split //) {$hash{$_}++};
> print "$_" if $hash{v}<=1 && $hash{c}<=2 &&
> $hash{c}>=1 && $hash{i}<=1 && $hash{n}<=1 && $hash{t}<=1 && $hash{e}<=1;
> }
> }
>
> Does somebody have a more elegant solution?

That would, of course, depend on your elegance metric.

while (<>) {
print if /c/ && !/[^aceintv]/ && !/([eintv]).*\1/ && !/([ac]).*\1.*\1/;
}

(The outer loop can be replaced by invoking perl with the -n switch).

Tassilo v. Parseval

unread,
Nov 7, 2002, 1:06:06 PM11/7/02
to
Also sprach nob...@mail.com:

> "Gregory Toomey" <nob...@noplace.com> wrote in message news:<01c2864c$6cb47f00$88498a90@gmtoomey>...
>
>> Subject: Perfecting my Perl
>
> The subject line should have contained the phase "perl golf".

Not necessarily. I am not inclined to see every elegant Perl solution as a
piece of Perl golf. Sometimes more verbose code can have its own air of
elegance. See CPAN, hardly a golf parcours.

Gregory Toomey

unread,
Nov 7, 2002, 3:08:44 PM11/7/02
to

Tassilo v. Parseval <tassilo....@post.rwth-aachen.de> wrote in article
<aqe2n4$7eu$1...@nets3.rz.RWTH-Aachen.DE>...


> The following posted on request sent in a personal mail from Cameron
> Dorey (her newsservice appears to be down):
>
> Gregory Toomey wrote:
>
> >
> > My solution:
> > Using the English language word list at www.wordlist.sourceforge.net/
,
>
>
> Is this the right URL? My computer cannot find it, and it looks like a
good
> site to test some things I'm doing.

Sorry its http://wordlist.sourceforge.net/

I use
"SCOWL (Spell Checker Oriented Word Lists) is a collection of word lists
split up in various sizes, and other categories, intended to be suitable
for use in spell checkers. However, I am sure it will have numerous other
uses as well. "

There are some 670,000 words if you add all the sublists together.

gtoomey

Gregory Toomey

unread,
Nov 7, 2002, 3:13:20 PM11/7/02
to
Julia deSilva <j...@trumpetweb.co.uk> wrote in article
<xjty9.34449$xF....@news-binary.blueyonder.co.uk>...

> > Does somebody have a more elegant solution?
> >
> > gtoomey
>
> Try : "Get a Life !"

There are cash prizes. I used Perlt to solve a more complex transposition
cipher problem in the same magazine.

gtoomey

--Rick

unread,
Nov 7, 2002, 4:17:12 PM11/7/02
to

"Tassilo v. Parseval" <tassilo....@post.rwth-aachen.de> wrote in
message news:aqe2n4$7eu$1...@nets3.rz.RWTH-Aachen.DE...

| The following posted on request sent in a personal mail from Cameron
| Dorey (her newsservice appears to be down):
|
| Gregory Toomey wrote:
|
| >
| > My solution:
| > Using the English language word list at
www.wordlist.sourceforge.net/ ,
|
|
| Is this the right URL? My computer cannot find it, and it looks like
a good
| site to test some things I'm doing.
|

Try this:
http://wordlist.sourceforge.net/

--Rick


Benjamin Goldberg

unread,
Nov 7, 2002, 5:46:50 PM11/7/02
to
nob...@mail.com wrote:
[snip]

> > Does somebody have a more elegant solution?
>
> That would, of course, depend on your elegance metric.
>
> while (<>) {
> print if /c/ && !/[^aceintv]/
> && !/([eintv]).*\1/ && !/([ac]).*\1.*\1/;
> }
>
> (The outer loop can be replaced by invoking perl with the -n switch).

I would replace each '.*' in the regexen with '.*?', for slightly
improved efficiency.

Also, perhaps a check for length() <= 9.

--
my $n = 2; print +(split //, 'e,4c3H r ktulrnsJ2tPaeh'
."\n1oa! er")[map $n = ($n * 24 + 30) % 31, (42) x 26]

Jay Tilton

unread,
Nov 7, 2002, 6:35:39 PM11/7/02
to
"Gregory Toomey" <nob...@noplace.com> wrote:

: I'm helping a relative with some word puzzles but the solution I've come up

Depends entirely on how you want to measure elegance.

Here's one I've had for a while. It started life as a golfish
one-liner, so clarity takes a shot on the chin. The basic idea is the
same as yours except the letters aren't hardcoded, and there isn't a
nicely abstract way to glue in the "must contain 'c'" requirement.

#!perl -p
sub f{my%w;$w{$_}++for/./g;%w}
%j=f;for$k(keys%j){$_ x=$j{$k}<=$i{$k}}
BEGIN{
die("Usage: $0 [letters] [dictionary file]")unless@ARGV==2;
$_=shift;%i=f
}

If you anticipate scrabbling many lettersets in one run, there is
obvious benefit in keeping the word list around in some kind of data
structure; a hash-of-arrays of words that are anagrams of each other
seems a decent choice. From there it's just hash lookups on letterset
permutations. Add a simple filtering callback mechanism, whatever
other bells and whistles you want, et voila.

#!perl
use warnings;
use strict;
print "$_\n"
for scrabble(
letters => 'aacceintv',
filter => sub{$_[0] =~ /c/}
);

sub scrabble {
my %args = @_;
$args{filter} ||= sub{1};
my $anagrams = wordlist();
my @ret;
for( permute_letters( $args{letters} ) ) {
next unless $args{filter}->($_);
push @ret, @{$anagrams->{$_}}
if defined $anagrams->{$_};
}
return @ret;
}

sub uniq {
my %seen;
@seen{@_} = ();
return keys %seen;
}

sub permute_letters {
my @elems = sort $_[0] =~ /./g;
my @perms;
for my $mask ( 1 .. (1<<@elems) - 1 ) {
push @perms, join '',
map $mask & 1<<$_
? $elems[$_]
: '',
0..$#elems;
}
return uniq(@perms);
}

{
my $words; # crude memoization of the sub's only return
sub wordlist {
unless( defined $words ) {
print "Reading word list...";
open WORDS, '<', 'wordlist.txt' or die $!;
while(<WORDS>) {
chomp;
my $key = join '', sort /./g;
push @{$words->{$key}}, $_;
}
close WORDS;
print "Done.\n";
}
return $words;
}
}

Gregory Toomey

unread,
Nov 7, 2002, 6:49:22 PM11/7/02
to
Thanks - that's lots of useful info. Constructing an anagram dictionary
would be very helpful too.

gtoomey

0 new messages