Как я добавляю элементы от одного массива Perl, которые уже не находятся в другом массиве?

Необходимо удалить столбцы va, detail и detail1 из выражения group by и применить функции агрегирования для всех них в списке выбора, как показано в следующем:

    with pu_sum_ebenen as
    (
     select date'2019-01-31' - level + 1 datum,
            2*level as va,
            (31 - level) as detail,
            (90 - 2*level) detail1,
            (100- level) as ebene1 
       from dual
    connect by level <= 31   
    )
    select
      extract(year from datum) jahr,
      extract(month from datum) monat,
      sum(va),
      max(detail),
      avg(detail1),
      sum(ebene1) ebene1
    from pu_sum_ebenen
    group by
      extract(year from datum),
      extract(month from datum);

    JAHR    MONAT   SUM(VA) MAX(DETAIL) AVG(DETAIL1)    EBENE1
    2019        1     306       30          72           1547
    2018       12     686       13          41           1057
[116 ] который возвращает строки только за месяцы.

10
задан brian d foy 13 January 2010 в 14:52
поделиться

5 ответов

my %k;
map { $k{$_} = 1 } @mylist1;
map { $k{$_} = 1 } @mylist2;
@mylist2 = keys %k;

Кроме того:

my %k;
map { $k{$_} = 1 } @mylist2;
push(@mylist2, grep { !exists $k{$_} } @mylist1);

На самом деле - они могли бы быть неправильными, потому что они не составляют, могли ли дубликаты существовать в любом из исходных списков.

Вы не сказали в своем вопросе, как ли списки, предполагается, представляют наборы (который не может содержать дубликаты), или просто перечисляет. То, что Вы эффективно хотите @mylist2 = @mylist1 U @mylist2 предполагает, что Вы рассматриваете их как наборы.

Править: измененный инкремент для присвоения - сохраняет чтение значения хэш-функции

12
ответ дан 3 December 2019 в 14:00
поделиться

Вы могли просто использовать List::MoreUtils модуль uniq:

use List::MoreUtils qw(uniq);

my @mylist1;
push( @mylist1, "A" );
push( @mylist1, "B" );
push( @mylist1, "C" );

my @mylist2;
push( @mylist2, "A" );
push( @mylist2, "D" );
push( @mylist2, "E" );

@mylist2 = uniq( @mylist1, @mylist2 );

printf "%s\n", ( join ',', @mylist2 );    # A,B,C,D,E
23
ответ дан 3 December 2019 в 14:00
поделиться

[Исходный ответ с 27.11.2008 вниз к "Начиная с вопроса"; анализ оттуда является новым с 29.11.2008.]

Самый быстрый - не уверенный. Это работает, хотя это не симпатично:

#!/bin/perl -w
use strict;

my @mylist1;
push(@mylist1,"A");
push(@mylist1,"B");
push(@mylist1,"C");

my @mylist2;
push(@mylist2,"A");
push(@mylist2,"D");
push(@mylist2,"E");

sub value_in
{
    my($value, @array) = @_;
    foreach my $element (@array)
    {
        return 1 if $value eq $element;
    }
    return 0;
}

@mylist2 = (@mylist2, grep { ! value_in($_, @mylist2) } @mylist1);

print sort @mylist2, "\n";

Это старается не преобразовывать массивы в хеши - но для больших массивов, value_in sub может быть медленным.

Так как вопрос был, "каков самый быстрый метод", я сделал некоторое сравнительное тестирование. К моему совершенно не обширному удивлению мой метод был самым медленным. Несколько к моему удивлению самый быстрый метод не был из Списка:: MoreUtils. Вот тестовый код и результаты - использование измененной версии моего первоначального предложения.

#!/bin/perl -w
use strict;
use List::MoreUtils  qw(uniq);
use Benchmark::Timer;

my @mylist1;
push(@mylist1,"A");
push(@mylist1,"B");
push(@mylist1,"C");

my @mylist2;
push(@mylist2,"A");
push(@mylist2,"D");
push(@mylist2,"E");

sub value_in
{
    my($value) = shift @_;
    return grep { $value eq $_ } @_;
}

my @mylist3;
my @mylist4;
my @mylist5;
my @mylist6;

my $t = Benchmark::Timer->new(skip=>1);
my $iterations = 10000;

for my $i (1..$iterations)
{
    $t->start('JLv2');
    @mylist3 = (@mylist2, grep { ! value_in($_, @mylist2) } @mylist1);
    $t->stop('JLv2');
}
print $t->report('JLv2');

for my $i (1..$iterations)
{
    $t->start('LMU');
    @mylist4 = uniq( @mylist1, @mylist2 );
    $t->stop('LMU');
}
print $t->report('LMU');

for my $i (1..$iterations)
{
    @mylist5 = @mylist2;
    $t->start('HV1');
    my %k;
    map { $k{$_} = 1 } @mylist5;
    push(@mylist5, grep { !exists $k{$_} } @mylist1);
    $t->stop('HV1');
}
print $t->report('HV1');

for my $i (1..$iterations)
{
    $t->start('HV2');
    my %k;
    map { $k{$_} = 1 } @mylist1;
    map { $k{$_} = 1 } @mylist2;
    @mylist6 = keys %k;
    $t->stop('HV2');
}
print $t->report('HV2');


print sort(@mylist3), "\n";
print sort(@mylist4), "\n";
print sort(@mylist5), "\n";
print sort(@mylist6), "\n";

Black JL: perl xxx.pl
9999 trials of JLv2 (1.298s total), 129us/trial
9999 trials of LMU (968.176ms total), 96us/trial
9999 trials of HV1 (516.799ms total), 51us/trial
9999 trials of HV2 (768.073ms total), 76us/trial
ABCDE
ABCDE
ABCDE
ABCDE
Black JL:

Это - Perl 5.10.0 скомпилированных для 32-разрядного SPARC с кратностью на старинном Sun E450 под управлением Солярис 10.

Я полагаю, что тестовые установки справедливы; они все генерируют свой ответ в новый массив, отдельный от mylist1 и mylist2 (так mylist1, и mylist2 может быть снова использован для следующего теста). Ответ определял HV1 (значения хэш-функции 1) имеет синхронизацию, запускаются после того, как присвоение на @mylist5, который я думаю, корректно. Однако, когда я сделал синхронизацию с запуском перед присвоением, это было все еще самым быстрым:

Black JL: perl xxx.pl
9999 trials of JLv2 (1.293s total), 129us/trial
9999 trials of LMU (938.504ms total), 93us/trial
9999 trials of HV1 (505.998ms total), 50us/trial
9999 trials of HV2 (756.722ms total), 75us/trial
ABCDE
ABCDE
ABCDE
ABCDE
9999 trials of HV1A (655.582ms total), 65us/trial
Black JL:
2
ответ дан 3 December 2019 в 14:00
поделиться

Из-за Ваш" (ABCDE)" комментарий, я предполагаю, что Вы на самом деле имели в виду нажатие на mylist1 те элементы в mylist2, которые не находятся в mylist1. Если это предположение является неправильным, необходимо сказать что-то о том, в каком порядке Вы хотите вещи закончиться.

Во-первых, хранилище, какие элементы находятся в mylist1 в хеше, затем продвигает все элементы в mylist2, не найденном в хеше на mylist1.

my %in_mylist1;
@in_mylist1{@mylist1} = ();
push @mylist1, grep ! exists $in_mylist1{$_}, @mylist2;
1
ответ дан 3 December 2019 в 14:00
поделиться
my(%work);
@work{@mylist1, @mylist2} = undef;
@mylist2 = sort keys %work;
0
ответ дан 3 December 2019 в 14:00
поделиться
Другие вопросы по тегам:

Похожие вопросы: