[Date Prev][Date Next][Thread Prev][Thread Next] [Search] [Date Index] [Thread Index]

Re: [FWP] Unsort/disperse a list



Tim Ayers wrote:
> I've written a function that evenly disperses a list.
> It doesn't work well
> when one of the groups has the majority of elements, 

=pod

Here's my whack at the problem.

It does handle well the case where one value has many more
occurrences than any others.

O.k., it's not a fun solution, but it was fun to write.

=cut

# takes a bag; returns the same bag but elements desorted.
sub unsort {
  my %h;
  for ( @_ ) { push @{$h{$_}}, $_; }
  my( $b, @bins ) = sort { @$a <=> @$b } values %h;
  my @result = @$b;
  for $b ( @bins ) { @result = intersperse( $b, \@result ); }
  @result
}

sub take_one {
  my( $counter_sr, $source_ar ) = @_;
  ${$counter_sr}++;
  shift @$source_ar
}

sub intersperse {
  my( $aa, $ab ) = @_; # two arrays, by ref.
  @$aa > @$ab and ( $aa, $ab ) = ( $ab, $aa );
  # so that @$aa is the shorter array,
  # and @$ab is the longer array.

  my $ratio = @$ab / @$aa;
  my @accum;
  my( $na, $nb ) = (0,0);

  # take one from each, to start with:
  push @accum, take_one( \$na, $aa );
  push @accum, take_one( \$nb, $ab );

  while ( @$aa and @$ab ) {
    push @accum, take_one(
      $nb / $na < $ratio
        ? ( \$nb, $ab )
        : ( \$na, $aa )
    );
  }

  ( @accum, @$ab, @$aa )
}


==== Want to unsubscribe from Fun With Perl?  Well, if you insist...
==== Send email to <fwp-request@technofile.org> with message _body_
====   unsubscribe