Удалить даже количество дубликатов из массива - PullRequest
0 голосов
/ 29 апреля 2018

у меня есть массив

[ 1, 0, 0, 0, 5, 2, 4, 5, 2, 2 ]

Мне нужно удалить четное количество дубликатов.

Это означает, что если значение появляется в массиве четное количество раз, удалите их все, но если оно появится нечетное количество раз, оставьте только один.

Результат из вышеприведенного массива должен быть

[ 1, 0, 2, 4 ]

Как я могу это сделать?

Ответы [ 4 ]

0 голосов
/ 30 апреля 2018

У вас есть куча ответов, вот еще:

use strict;
use warnings;
use Data::Dumper;

my $input = [ 1, 0, 0, 0, 5, 2, 4, 5, 2, 2 ];
my $output = dedupe_evens($input);

print Data::Dumper->Dump([$input, $output], ['$input', '$output']);

exit;


sub dedupe_evens {
    my($input) = @_;

    my %seen;
    $seen{$_}++ foreach @$input;
    my @output = grep {
        my $count = delete $seen{$_};  # only want first occurrence
        $count && $count % 2;
    } @$input;

    return \@output;
}

, который производит этот вывод (переформатирован для краткости):

$input  = [ 1, 0, 0, 0, 5, 2, 4, 5, 2, 2 ];
$output = [ 1, 0, 2, 4 ];
0 голосов
/ 29 апреля 2018

См. Комментарии, чтобы увидеть, как это возможное решение делает.

#!/usr/bin/perl

use strict;
use warnings;

my @a = qw(1 0 0 0 5 2 4 5 2 2);

# Move through the array.
for (my $i = 0; $i < scalar(@a); ) {
  # Move through the positions at and ahead of current position $i
  # and collect all positions $j, that share the value at the
  # current position $i.
  my @indexes;
  for (my $j = $i; $j < scalar(@a); $j++) {
    if ($a[$j] == $a[$i]) {
      push(@indexes, $j);
    }
  }

  if (scalar(@indexes) % 2) {
    # If the number of positions collected is odd remove the first
    # position from the collection. The number of positions in the
    # collection is then even afterwards.
    shift(@indexes);
    # As we will keep the value at the current position $i no new
    # value will move into that position. Hence we have to advance
    # the current position.
    $i++;
  }

  # Move through the collected positions.
  for (my $k = 0; $k < scalar(@indexes); $k++) {
    # Remove the element at the position as indicated by the
    # $k'th element of the collect positions.
    # We have to subtract $k from the collected position, to
    # compensate for the movement of the remaining elements to the
    # left.
    splice(@a, $indexes[$k] - $k, 1);
  }
}

print("@a");
0 голосов
/ 29 апреля 2018

Удаление дубликатов обычно выполняется следующим образом:

use List::Util 1.44 qw( uniqnum );

@a = uniqnum @a;

или

my %seen;
@a = grep { !$seen{$_}++ } @a;

Чтобы достичь того, что вы хотите, нам просто нужна цепочка grep, которая удаляет другие нежелательные элементы.

use List::Util 1.44 qw( uniqnum );

@a = uniqnum grep { $counts{$_} % 2 } @a;

или

my %seen;
@a = grep { !$seen{$_}++ } grep { $counts{$_} % 2 } @a;

или

my %seen;
@a = grep { ( $counts{$_} % 2 ) && !$seen{$_}++ } @a;

Приведенные выше решения основаны на подсчете каждого значения. Чтобы получить это, мы можем использовать следующее:

my %counts;
++$counts{$_} for @a;

Все вместе:

my ( %counts, %seen );
++$counts{$_} for @a;
@a = grep { ( $counts{$_} % 2 ) && !$seen{$_}++ } @a;

Обратите внимание, что эти методы удаления дубликатов сохраняют порядок элементов (сохраняя первый дубликат). Это более эффективно (O (N)), чем использование sort (O (N log N)), чтобы избежать создания чего-то недетерминированного.

0 голосов
/ 29 апреля 2018

Это действительно не сложно, и это очень плохая форма, чтобы вообще не пытаться решить это самостоятельно. Я хотел бы, чтобы кто-то, кто опубликовал подобные вопросы, описал, как он чувствует себя комфортно, заставляя кого-то другого делать свою работу за них. Даже сложные кроссворды не получают такой поток запросов на решение, но, возможно, в этом случае вам платят за решение, написанное кем-то другим? Почему это не проблема для вас?

  • Создайте хэш для вычисления текущего значения для каждого значения

  • используйте $_ % 2 определите новый окончательный счет

  • Разобрать хеш для нового массива

my $array = [ 1, 0, 0, 0, 5, 2, 4, 5, 2, 2 ];

my @new_array = do {

    my %counts;

    ++$counts{$_} for @$array;

    map {
        ( $_ ) x ( $counts{$_} % 2 )
    } sort { $a <=> $b } keys %counts;
};

use Data::Dump;
dd \@new_array;

выход

[0, 1, 2, 4]
...