sub fold {
my $self = shift;
return if ! @{$self->{data}};
my $array = $self->{data};
my $date_grouped = 0;
my $campaign_grouped = 0;
foreach(@{$self->{groups}}) {
$date_grouped = 1 if $_ eq 'date';
$campaign_grouped = 1 if $_ eq 'campaign';
}
my $merge_index = 0;
my $points_needed = $campaign_grouped + $date_grouped;
@$array = sort {fold_sort($campaign_grouped,$date_grouped)} @$array;
for(my $current_index=0; $current_index<@$array; $current_index++) {
my $el = $array->[$current_index];
if($merge_index == $current_index) {
next;
}
#compare current element to merge element
my $match = 0;
my $merge = $array->[$merge_index];
$match++ if $date_grouped &&
$el->{date} eq $merge->{date};
$match++ if $campaign_grouped &&
$el->{campaign_id} == $merge->{campaign_id};
#if we can fold the array elements then do so and remove the
#look ahead element
if($match == $points_needed) {
$merge->{views} += $el->{views};
$merge->{clicks} += $el->{clicks};
my $del = splice(@$array,$current_index,1);
$current_index--;
} else {
$merge_index++;
}
}
}
Anyone have a better way of doing this? The fold_sort function just orders the array based on how were are grouping the elements.
Thanks,
Kenny
PS - I was not sure of what to call this so I figured "Array Folding" was a good enough term...if there is another term that people use let me know please :-)
@$array = sort {fold_sort($campaign_grouped,$date_grouped)} @$array;
Can you also provide some data samples? Input, actual output, and desired output?
sub fold {
my $self = shift;
my $array = $self->{data};
return unless $array && @$array;
my %groups = map { $_ => 1 } @{$self->{groups};
my @keys = grep { $groups{$_} } qw/ date campaign /;
my %h;
foreach my $el ( @$array ){
my $k = join ":", @{$_}{@keys}; # This only works if the date & campaign values do not contain ':'
if( exists $h{$k} ) {
$h{$k}->{views} += $el->{views};
$h{$k}->{clicks} += $el->{clicks};
}else{
$h{$k} = $el;
}
}
@$array = sort { fold_sort($groups{campaign},$groups{date}) } values %h;
}
Note that the basic approach is to hash up on the commonality (date and/or campaign) to combine everything, then take those values and sort for final result.
sub fold {
my $self = shift;
return if !@{ $self->{data} };
my %h;
for ( @{ $self->{data} } ) {
push @{ $h{ join $;, @$_{ @{ $self->{groups} } } } }, $_;
}
$self->{data} = [
map {
my $x = {
date => $h{$_}->[0]->{date},
campaign_id => $h{$_}->[0]->{campain_id},
};
for ( @{ $h{$_} } ) {
$x->{views} += $_->{views};
$x->{clicks} += $_->{clicks};
}
$x;
} keys %h
];
}
perlmonks.org content © perlmonks.org and BarMeister, borisz, davidrw
prlmnks.org © 2006 edmund von der burg (eccles & toad)
v 0.03