Training, Open Source computer languages
PerlPHPPythonMySQLApache / TomcatTclRubyJavaC and C++LinuxCSS 
Search for:
Home Accessibility Courses Diary The Mouth Forum Resources Site Map About Us Contact
 
For 2023 (and 2024 ...) - we are now fully retired from IT training.
We have made many, many friends over 25 years of teaching about Python, Tcl, Perl, PHP, Lua, Java, C and C++ - and MySQL, Linux and Solaris/SunOS too. Our training notes are now very much out of date, but due to upward compatability most of our examples remain operational and even relevant ad you are welcome to make us if them "as seen" and at your own risk.

Lisa and I (Graham) now live in what was our training centre in Melksham - happy to meet with former delegates here - but do check ahead before coming round. We are far from inactive - rather, enjoying the times that we are retired but still healthy enough in mind and body to be active!

I am also active in many other area and still look after a lot of web sites - you can find an index ((here))
subset a list

Posted by gmeyer (gmeyer), 16 October 2003
Hi Graham,

I was wondering if there is a quick way of finding out if a list of values is a subset of another list of values?

Something along these lines would be nice...but of course this doesnt work!

@biglist=('one', 'two', 'three');
@smallist=('one','three');
$true = grep (/@smallist/i, @biglist);
if ($true) { print "\nYes the smallist is a subset of biglist") }

Great forum guys.
Gordon

Posted by gmeyer (gmeyer), 16 October 2003
Just noticed that this should be in the perl programming language section of course!..sorry.

Posted by John_Moylan (jfp), 16 October 2003
I may be talking rubbish. (believe me theres a good chance of this)..but

Could you flatten the arrays and test the strings against each other?

Code:
my @ary1 = qw(one two three four five six seven eight nine ten);
my @ary2 = qw(five six seven eight nine);

my $ary1string = join('', @ary1);
my $ary2string = join('', @ary2);

if($ary1string =~ /$ary2string/) {
   print "Is a subset";
}
else {
   print "Not";
}


Posted by admin (Graham Ellis), 16 October 2003
Why do the most interesting questions get posted while I'm on an intercontinentyal flight?  

I've got some ideas, but too tired to put them down in goon English tonight .... I'll follow up further in the morning.

Posted by admin (Graham Ellis), 17 October 2003
Flattening the arrays would work in some special circumstances - you would need both lists to be in the same order, and the items matching to follow directly after one another in the bigger list, amongst other constraints.

There's no one-liner to do what you want, Gordon (unless you make it a very long line with lots of ; s in it!).  Here is a "quick and dirty" fix:

Code:
@biglist=('one', 'two', 'three', 'four', 'five', 'six');
@smalllist=('one','three','seven');

$allin = 1;
foreach $item(@smalllist) {
       grep ($_ eq $item,@biglist) or $allin = 0;
       }

print "Result: $allin\n";


I've run this, fiddled the data, run it again .... it works fine.  In effect, you have a loop within a loop which is not going to be efficient, but at least I've had grep use "eq" rather that "=~", so that you're not doing huge numbers of regular expression check.

Once you set $allin to 0 in my example, you know your test has failed so there's no point in carrying on - thus, you can identify failed matches quicker using last:

Code:
@biglist=('one', 'two', 'three', 'four', 'five', 'six','seven');
@smalllist=('one','three','seven');

$allin = 1;
foreach $item(@smalllist) {
       grep ($_ eq $item,@biglist) or $allin = 0 or last;
       }

print "Result: $allin\n";


Now - you ask if there's a quick way of finding out if one list is in another, but I give you a solution that's a loop, and within it you have a grep which has an embedded loop checking all elements.  Perhaps not your definition of quick.   If you have a whole series of smalllists to check against one biglist, or if both lists contain quite a lot of elements, you might like to use the power of a hash to set up a table of elements that exist in the big list.   Here's what I mean:

Code:
foreach $item ('one', 'two', 'three', 'four', 'five', 'six','seven') {
       $have{$item} = 1;
       }
@smalllist=('one','three','eight');

$allin = 1;
foreach $item(@smalllist) {
       $have{$item} or $allin=0 or last;
       }

print "Result: $allin\n";


The testing has now come down to a single simple loop that doesn't have to go through all the elements of another list.  Neat trick, learnt from the masters in books like the Perl cookbooks, and something we employ ourselves in quite a number of our own scripts.

Posted by gmeyer (gmeyer), 17 October 2003
Thx guys,

I have gone for the final solution transposing into a hash.



Posted by Custard (Custard), 19 October 2003
Hiya,

I don't want to seem 'clever' but as a matter of interest, I was reading a book 'algorithms in perl' last night that had a whole section on sets.

One thing I saw that would be most useful in your case would be ths hash slice method.
So, to create the set you (could) use

@set{ 'one','two','three' } = ();

or

@set{ @array } = ();


This defines a hash of undef's, which is quicker. Also the search loop will have to test for exists $set{ $item }, which is also quicker.
Aparrently if you define undef as a value in a hash, perl doesn't have to add a value, and using exists doesn't have to retrieve the value.
Also, undef is a reference to a single object, and if you had used '1' then each '1' would be a separate object.
It's also a one liner.

Everyday's a school day with perl...

hth
Bruce

PS. I've not tried it yet ;-o)

Posted by admin (Graham Ellis), 19 October 2003
Neat thought .... yes .... I'll have to try that sometime.  I would suggest that anyone using undef'd members of a hash adds a few comments to their source!



This page is a thread posted to the opentalk forum at www.opentalk.org.uk and archived here for reference. To jump to the archive index please follow this link.

You can Add a comment or ranking to this page

© WELL HOUSE CONSULTANTS LTD., 2024: Well House Manor • 48 Spa Road • Melksham, Wiltshire • United Kingdom • SN12 7NY
PH: 01144 1225 708225 • FAX: 01144 1225 793803 • EMAIL: info@wellho.net • WEB: http://www.wellho.net • SKYPE: wellho