logan@rockville.dg.com (James L. Logan) (07/03/90)
Is there a better or faster way to drop all elements in set B that intersect with set A? Here's what I've got so far: open(FILE1, "file1") || die; @A = <FILE1>; close(FILE1) || die; open(FILE2, "file2") || die; @B = <FILE2>; close(FILE2) || die; foreach $element (@A) { foreach (@B) { if (/^$element$/) { $_ = ''; last; } } } print @B; Also, how can I delete the element that was matched in @B, while also shortening the array by one element; rather than just setting the element to the null string? Thanks, -Jim -- James Logan UUCP: uunet!inpnms!logan Data General Telecommunications Inet: logan@rockville.dg.com 2098 Gaither Road Phone: (301) 590-3198 Rockville, MD 20850
tneff@bfmny0.BFM.COM (Tom Neff) (07/03/90)
In article <601@inpnms.ROCKVILLE.DG.COM> logan@rockville.dg.com (James L. Logan) writes: >Is there a better or faster way to drop all elements in set B that >intersect with set A? Here's what I've got so far: ... > foreach $element (@A) { > foreach (@B) { > if (/^$element$/) { > $_ = ''; > last; > } > } > } ... Try this: @B=grep(!do {$x=$_; grep($x eq $_,@A);},@B); >Also, how can I delete the element that was matched in @B, while >also shortening the array by one element; rather than just >setting the element to the null string? Should do it. -- "UNIX should be used :: Tom Neff <tneff@bfmny0.BFM.COM> or as an adjective." -- AT&T :: ...uunet!bfmny0!tneff (UUCP only)
tell@oscar.cs.unc.edu (Stephen Tell) (07/03/90)
In article <601@inpnms.ROCKVILLE.DG.COM> logan@rockville.dg.com (James L. Logan) writes: >Is there a better or faster way to drop all elements in set B that >intersect with set A? Here's what I've got so far: > open(FILE1, "file1") || die; > @A = <FILE1>; > close(FILE1) || die; > > open(FILE2, "file2") || die; > @B = <FILE2>; > close(FILE2) || die; > > foreach $element (@A) { > foreach (@B) { > if (/^$element$/) { > $_ = ''; > last; > } > } > } > print @B; >Also, how can I delete the element that was matched in @B, while >also shortening the array by one element; rather than just >setting the element to the null string? Its called splice(@array, offset, length, [replace]) "Delete length elements from @array starting at offset and return them, optionaly replacing them with new elements." > Thanks, > -Jim This is my first comp.lang.perl posting with a coding suggestion, so be gentle, guys! It seems that using an associative array to say "did we see this anywhere" would help a lot over the O(n**2) approach above. You said these are sets, if the order in which B gets printed matters, this goes out the window. But try: open(FILE1, "file1") || die; @A=<FILE1>; close(FILE1) || die; open(FILE2, "file2") || die; while(<FILE2>) { $B{$_} = 1; } close(FILE2) || die; foreach $element (@A) { if ($B{$element} { delete($B{$element}); } } print keys(%B); Is there a better way to read FILE2 into an associative array like this? Perhaps the ability to say keys(%B) = <FILE2>; -------------------------------------------------------------------- Steve Tell e-mail: tell@wsmail.cs.unc.edu usmail: #5L Estes Park apts CS Grad Student, UNC Chapel Hill. Carrboro NC 27510
merlyn@iwarp.intel.com (Randal Schwartz) (07/04/90)
In article <601@inpnms.ROCKVILLE.DG.COM>, logan@rockville (James L. Logan) writes: | Is there a better or faster way to drop all elements in set B that | intersect with set A? Here's what I've got so far: | | open(FILE1, "file1") || die; | @A = <FILE1>; | close(FILE1) || die; | | open(FILE2, "file2") || die; | @B = <FILE2>; | close(FILE2) || die; | | foreach $element (@A) { | foreach (@B) { | if (/^$element$/) { | $_ = ''; | last; | } | } | } | print @B; | | Also, how can I delete the element that was matched in @B, while | also shortening the array by one element; rather than just | setting the element to the null string? Well, I'd attack it something like this: open(F1,"file1") || die "cannot open file1: $!"; while (<F1>) { $saw{"$_"}++; } close(F1); open(F2,"file2") || die "cannot open file2: $!"; while (<F2>) { print unless $saw{$_}; } close(F2); Using the keys of an assoc array as a set-type is a very handy idiom. print "Just another Perl hacker," -- /=Randal L. Schwartz, Stonehenge Consulting Services (503)777-0095 ==========\ | on contract to Intel's iWarp project, Beaverton, Oregon, USA, Sol III | | merlyn@iwarp.intel.com ...!any-MX-mailer-like-uunet!iwarp.intel.com!merlyn | \=Cute Quote: "Welcome to Portland, Oregon, home of the California Raisins!"=/
logan@rockville.dg.com (James L. Logan) (07/04/90)
In article <15631@bfmny0.BFM.COM> tneff@bfmny0.BFM.COM (Tom Neff) writes:
#
# @B=grep(!do {$x=$_; grep($x eq $_,@A);},@B);
#
Could someone explain this construct? I've only been using perl
for a week now...
-Jim
--
James Logan UUCP: uunet!inpnms!logan
Data General Telecommunications Inet: logan@rockville.dg.com
2098 Gaither Road Phone: (301) 590-3198
Rockville, MD 20850
lwall@jpl-devvax.JPL.NASA.GOV (Larry Wall) (07/04/90)
In article <604@inpnms.ROCKVILLE.DG.COM> logan@rockville.dg.com (James L. Logan) writes: : In article <15631@bfmny0.BFM.COM> tneff@bfmny0.BFM.COM (Tom Neff) writes: : # : # @B=grep(!do {$x=$_; grep($x eq $_,@A);},@B); : # : : Could someone explain this construct? I've only been using perl : for a week now... That's just a funny way of writing two nested loops. It's more or less equivalent to @outer_result = (); foreach $_ (@A) { $x = $_; @inner_result = (); foreach $_ (@B) { push(@inner_result,$_) if $x eq $_; } push(@outer_result, $_) if @inner_result; } @B = @outer_result; As such, it's just another O(n**2) algorithm. Better to use the associative array method mentioned earlier, which is basically a linear algorithm. Larry