Как мы можем отсортировать столбец 1, а затем столбец 2 пользовательских данных, используя Perl - PullRequest
2 голосов
/ 07 декабря 2011

Я новичок в программировании на Perl. Я хочу прочитать данные файла, затем отсортировать запись в столбце 1, а затем в столбце 2 (удалить повторную запись) и сохранить отсортированную запись в другом файле. Ниже приведены мои данные

Первый столбец и второй столбец разделены вкладкой

 user1 name       user2 name

    abc               xyz
    adc               xyz
    abc               xyz
    pqr               tyu
    xyz               abc
    tyu               pqr
    abc               pqr

В этом примере я хочу сначала отсортировать запись по имени пользователя1, а затем по имени пользователя2, а также во время сортировки я хочу удалить повторяющуюся запись.

Вывод должен быть следующим

user1 name        user2 name
  abc              pqr
  abc              xyz
  adc              xyz
  pqr              tyu
  tyu              pqr
  xyz              abc

Пожалуйста, дайте мне знать, как мы можем реализовать этот Perl?

Ответы [ 4 ]

4 голосов
/ 07 декабря 2011
#!/usr/bin/env perl
use strict;
use warnings;
my @list = <DATA>;
my $prev;
for (sort @list) {
    next if $prev && $_ eq $prev;
    $prev = $_;
    print;
}
__DATA__
    abc               xyz
    adc               xyz
    abc               xyz
    pqr               tyu
    xyz               abc
    tyu               pqr
    abc               pqr
1 голос
/ 08 декабря 2011

Все зависит от того, как вы храните свои данные. Я не уверен, как вы планируете хранить вашу информацию, так как вы в классе и можете или не могли узнать о ссылках. Например, если вы не знаете ссылок, вы можете сделать что-то вроде этого:

my @array;
foreach my $value (<INPUT>) {
   chomp $value;
   my ($user1, $user2) = split (" ", $value);
   push (@array, "$user1:$user2");
}

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

Если вы знаете о ссылках, вы, вероятно, сделаете это:

my @array;
foreach my $value (<INPUT>) {
   chomp $value;
   my @line = split (" ", $value);
   push (@array, \@line);
}

Что я могу вам сказать, так это то, что подпрограмма sort позволяет вам создать функцию для сравнения и сортировки значений. Когда вы используете свою собственную функцию в sort, вы получаете два значения $a и $b, которые представляют значения, которые вы сортируете. Вы можете манипулировать ими, а затем возвращать -1, если $a меньше $b или 1, если $ a больше $b, или возвращать ноль, если они оба равны. Perl предоставляет вам два оператора <=> и cmp, чтобы сделать это немного проще.

Предположим, вы сохраняете значения как $user1:$user2, так как вы еще не узнали о ссылках. Ваша процедура сортировки может выглядеть следующим образом.

sub sort {
    my ($a_col1, $a_col2) = split (/:/, $a);
    my ($b_col1, $b_col2) = split (/:/, $b);

    # Now we compare $a to $b. First, we can compare the
    # User 1 column:

    if ($a_col1 lt $b_col1) {
        return -1;    #$a < $b
    }
    elsif ($a_col1 gt $b_col1) {
        return 1;     #$a > $b
    }

    # If we're down here, it's because column 1 matches
    # for both $a and $b. We'll have to compare column #2
    # to see which one is bigger.

    if ($a_col2 lt $b_col2) {
       return -1;   #$a < $b
    }
    elsif ($a_col2 gt $b_col2) {
       return 1;    #$a > $b
    }

    #We're down here because both column #1 and column #2 match for both
    #$a and $b. They must be equal

    return 0;
}

Теперь мой вид будет выглядеть примерно так:

my @new_array = sort(\&sort, @array);

Примечание : Я лично так не поступаю. Я бы, вероятно, использовал встроенный оператор cmp и воспользовался бы некоторыми сочетаниями клавиш. Однако я хотел разобрать это на части, чтобы вы могли понять.

Кстати, если учитель решит, что вы должны отсортировать второй столбец перед первым, вы можете легко изменить подпрограмму sort, просто изменив знаки «меньше» и «больше».


Вот моя тестовая программа:

#! /usr/bin/env perl

use strict;
use warnings;

#Putting my data in `@array`

my @array;
foreach my $entry (<DATA>) {
    chomp $entry;
    my ($user1, $user2) = split " ",  $entry;
    push @array, "$user1:$user2";
}

# Sorting my data

my @new_array = sort \&sort, @array;

#Now printing out my data nice and sorted...

foreach my $element (@new_array) {
    my ($user1, $user2) = split (/:/, $element);
    print "$user1\t\t$user2\n";
}

#
# END OF PROGRAM
##################################################

##################################################
# Sort subroutine I'm using to sort the data
#
sub sort {
    my ($a_col1, $a_col2) = split (/:/, $a);
    my ($b_col1, $b_col2) = split (/:/, $b);

    # Now we compare $a to $b. First, we can compare the
    # User 1 column:

    if ($a_col1 lt $b_col1) {
        return -1;    #$a < $b
    }
    elsif ($a_col1 gt $b_col1) {
        return 1;     #$a > $b
    }

    # If we're down here, it's because column 1 matches
    # for both $a and $b. We'll have to compare column #2
    # to see which one is bigger.

    if ($a_col2 lt $b_col2) {
        return -1;   #$a < $b

   }
    elsif ($a_col2 gt $b_col2) {
        return 1;    #$a > $b
    }

    #We're down here because both column #1 and column #2 match for both
    #$a and $b. They must be equal

    return 0;
}

__DATA__
david       fu
david       bar
albert      foofoo
sandy       barbar
albert      foobar
1 голос
/ 07 декабря 2011

Возможно, производственный код не достоин, но вот подход:

#!/usr/bin/perl

use strict;
use warnings;

my %seen;
print join "",
    grep {$_ !~ /^\s+$/ && !$seen{$_}++}
    sort {$a !~ /^ user/ <=> $b !~ /^ user/ || 
    $a cmp $b} <DATA>;

__DATA__
 user1 name       user2 name

    abc               xyz
    adc               xyz
    abc               xyz
    pqr               tyu
    xyz               abc
    tyu               pqr
    abc               pqr

Вывод:

 user1 name       user2 name
    abc               pqr   
    abc               xyz
    adc               xyz
    pqr               tyu
    tyu               pqr
    xyz               abc

Самой нетрадиционной частью здесь является условие сортировки $a !~ /^ user/ <=> $b !~ /^ user/.$a !~ /^ user/ оценивает 1 (true) для всех строк, кроме первой, где оно оценивается как 0 (false), поэтому заголовок ставится первым, а конечные строки переходят во второе условие сортировки, что приводит кжелаемый результат.

0 голосов
/ 08 декабря 2011

Или это может быть просто:

print sort <DATA>;

__DATA__
    abc xyz
    pqr tyu
    xyz abc
    adc xyz
    tyu pqr
    abc pqr
    abc xyz

Но только если ваши данные так просты, как это. Если данные в каждом столбце изменяются по длине, каждый столбец должен быть шириной самого длинного элемента. вот так:

__DATA__
    abc              |xyz       |<-- other data in record...
    pqrwf            |tyu       |<-- other data in record...
    xyzsder          |abc       |<-- other data in record...
    adca             |xyzghrt   |<-- other data in record...
    tyuvdfcg         |pqr       |<-- other data in record...
    abcvfgfaqrt      |pqrbb     |<-- other data in record...
    abcaaaaaaaaaaa   |xyz       |<-- other data in record...

В этом случае простая сортировка все еще работает, но обратите внимание, что эти столбцы дополнены пробелами, а не символами табуляции.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...