Re: sort an array according to another array
by halley (Prior) on Jun 03, 2003 at 20:19 UTC
|
Do benchmarking on your method, and any other method you come across. Here's my idea, but I'm sure there's others.
If @L's elements are unique, and @S is truly a subset of @L, then one way would be:
$i = 0;
%L = map { $_ => $i++ } @L;
@Ss = sort { $L{$a} <=> $L{$b} } @S;
It requires more intermediary storage, but perhaps a simpler operation.
Test results:
@L = qw(one two three four five six seven eight);
@S = qw(eight one five three);
@Ss = qw(one three five eight);
-- [ e d @ h a l l e y . c c ] | [reply] [d/l] [select] |
Re: sort an array according to another array
by sauoq (Abbot) on Jun 03, 2003 at 21:51 UTC
|
The problem is that you are stuck with lookups into the larger array and that's O(n). Your best choice if you have to do this a lot and the larger array isn't so large that memory usage would make it unfeasible, would be to make a hash keyed by the elements in the larger array where the values are those elements' indexes. Otherwise, what you are doing is pretty reasonable.
-sauoq
"My two cents aren't worth a dime.";
| [reply] |
Re: sort an array according to another array
by tye (Sage) on Jun 03, 2003 at 23:10 UTC
|
If the smaller list is a lot smaller and you want to do the same sort a lot more often than you want to change the large list, then things might run faster if you build a database (such as DB_File) mapping each member of the large list to its position (similar to other methods in this thread but using a tied hash).
The tied hash would not need to be built each time you sort. Otherwise, you've got to go through the large list linearly every time in order to build the large hash, which probably means that things won't run much faster than your current method.
- tye
| [reply] |
Re: sort an array according to another array
by Anonymous Monk on Jun 03, 2003 at 20:19 UTC
|
Well, unless something about your sorting mechanism is weird, sorting the subset by the same rules as the superset should produce a properly sorted set. | [reply] |
|
|
The sorted array is produced by a combination of several external applications and is the ultimate result of an initial data set of several hundred megs - a few weeks of work. The sorting of the smaller set is something I need to do quite often, there is just no way to repeat this process every time (nor any need).
| [reply] |
Re: sort an array according to another array
by jaa (Friar) on Jun 04, 2003 at 08:02 UTC
|
If I read your question correctly, you have something like this?
use strict;
my @universe = sort complex_sort (1001 ... 5000);
my @random_offsets = (503,1083,260,5,101);
my @subset = @universe[@random_offsets];
print "unsorted subset: @subset\n";
# Want subset in same complex_sort order as @universe
# Can do a quick sort on the index, as @universe
# is already in the order we want!
# Option 1:
@subset = @universe[sort( {$a <=> $b} @random_offsets)];
print "sorted subset: indicies: @subset\n";
# But if unable to determine the universe indicies
# in advance, we might have to sort the subset once
# Option 2:
@subset = sort complex_sort @subset;
print "sorted subset: complex_sort @subset\n";
sub complex_sort {
return $b <=> $a;
}
Regards
Jeff | [reply] [d/l] |
Re: sort an array according to another array
by wufnik (Friar) on Jun 04, 2003 at 08:58 UTC
|
here is something small you might like to try if
halley's hash above proves too chunky for your ZX81.
the following will deposit the sorted subset
in @uS; the memory consumued will be of the
order of the size of elements in the unsorted
list. so it will be kind to machines with less RAM.
if the unsorted list is short, the fact that the only a few
grep's will be employed will make the solution
reasonable in time too.
my @S=("tilly","zaxo","sauog","enlil","castaway","wufnik");
my @U = ("castaway","zaxo","wufnik","enlil");
my %uS = map { $tmp = $_; $tmp => grep { $S[$_] =~ /^$tmp$/ } (0..$#S)
+ } @U;
@uS = sort { $uS{$a} <=> $uS{$b} } @U;
print join "\n", @uS;
which produces
zaxo
enlil
castaway
wufnik
from the unsorted list above.
it freely admit it won't always be the fastest solution, but it will be kind, at least to those who like map & grep.
...wufnik
-- in the world of the mules there are no rules --
| [reply] [d/l] |
Re: sort an array according to another array
by aquarium (Curate) on Jun 04, 2003 at 01:55 UTC
|
i take it than when you traverse the larger array that you're looping through the index number. use that number as the key when you're creating the small hash. then a simple sort keys %small_hash gives them to you in order. | [reply] |
Re: sort an array ... another array (not reading closely enough)
by Enlil (Parson) on Jun 04, 2003 at 09:35 UTC
|
update: Is there an echo in here? ACK!! i just reread the start of this thread, and realized it was exactly the same thing as the OP is doing in the first place.
Here is my take on your problem. Take the Smaller array and create a hash on what exists in it. Then go through the larger array and grep the elements that exist in the hash created with the smaller array. And in the end it is sorted in the order things appear in the large array and contains only the things in the smaller array, as follows: use strict;
use warnings;
my @sorted = ("a" .. "z", "A" .. "Z");
my @needs_sorting = ( qw (P l E a S e s O r T) );
my %S;
@S{@needs_sorting} = ();
my @is_sorted = grep { exists $S{$_} } @sorted;
print join "|",@is_sorted;
| [reply] [d/l] |
|
|
superb. much nicer than my way of getting the subset's sorted order.
and still no megahash for the sorted set.
...wufnik
-- in the world of the mules there are no rules --
| [reply] |
Re: sort an array according to another array
by zentara (Cardinal) on Jun 04, 2003 at 15:41 UTC
|
| [reply] |