2012-02-28 4 views
3

Я охотился вокруг последние несколько дней для набора инструментов командной строки, в Perl или сценарий AWK, что позволит мне очень быстро перенести следующие данные:командной строки поворота

Row|Col|Val 
1|A|foo 
1|B|bar 
1|C|I have a real 
2|A|bad 
2|C|hangover 

в это :

A|B|C 
foo|bar|I have a real 
bad||hangover 

Обратите внимание, что есть только одно значение в наборе данных для каждой «ячейки» (то есть, как и в таблице, нет никаких дубликатов Row «1» Col «а»)

Я пробовал разные awk, она ll для переноса данных, но не может заставить их работать. Одна из моих идей заключалась в том, чтобы вырезать каждое значение «Col» в отдельный файл, а затем использовать командную строку «join», чтобы объединить их вместе «Row», но ДОЛЖЕН быть более простым способом. Я уверен, что это просто невероятно просто, но я немного борюсь.

Мои входные файлы имеют Cols A-G (в основном, включая строки переменной длины) и 10 000 строк. Если я могу избежать загрузки всего в память, это было бы огромным плюсом.

Пиво по почте для всех, у кого есть ответ!

Как всегда - большое спасибо за вашу помощь.

Cheers,

Джош

P.S. - Я немного удивлен тем, что для выполнения этого очень простого типа операции поворота/транспонирования нет привычной командной строки. Я посмотрел на http://code.google.com/p/openpivot/ и на http://code.google.com/p/crush-tools/, оба из которых, похоже, требуют агрегатных вычислений.

ответ

3

Я могу сделать это с gawk, но не с nawk.

#!/usr/local/bin/gawk -f 

BEGIN { 
    FS="|"; 
} 

{ 
    rows[$1]=1; cols[$2]=1; values[$1][$2]=$3; 
} 

END { 
    for (col in cols) { 
    output=output sprintf("|%s", col); 
    } 
    print substr(output, 2); 
    for (row in rows) { 
    output=""; 
    for (col in cols) { 
     output=output sprintf("|%s", values[row][col]); 
    } 
    print substr(output, 2); 
    } 
} 

И даже работает:

[email protected] $ cat data 
1|A|foo 
1|B|bar 
1|C|I have a real 
2|A|bad 
2|C|hangover 
[email protected] $ ./doit.gawk data 
A|B|C 
foo|bar|I have a real 
bad||hangover 
[email protected] $ 

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

UPDATE:

Per комментарии:

#!/usr/local/bin/gawk -f 

BEGIN { 
    FS="|"; 
} 

{ 
    rows[$1]=1; cols[$2]=1; values[$1,$2]=$3; 
} 

END { 
    for (col in cols) { 
    output=output sprintf("|%s", col); 
    } 
    print output; 
    for (row in rows) { 
    output=""; 
    for (col in cols) { 
     output=output "|" values[row,col]; 
    } 
    print row output; 
    } 
} 

И выход:

[email protected] $ ./doit.awk data 
|A|B|C 
1|foo|bar|I have a real 
2|bad||hangover 
[email protected] $ 
+0

ghoti - Святая корова, которая была быстрой! Кажется, я получаю синтаксические ошибки для следующих значений: значения [$ 1] [$ 2] = $ 3; и значения [row] [col]. Есть предположения? – Josh

+0

Выяснил это .... Исправьте следующее: значения [$ 1, $ 2] и значения [row, col] – Josh

+0

Используете ли вы awk или gawk? Если gawk, какая версия? Я не помню, когда добавлялись многомерные массивы, но это могло быть 3.1. Некоторые пакеты для Solaris или AIX или такие могут быть старше этого. Если вы используете FreeBSD, установите gawk из ports/lang/gawk. – ghoti

1

Просто используйте хэш. Если вы не хотите загружать их в память, вам могут понадобиться модули, такие как DBM::Deep и бэкэнд DBM.

my %table; 

my $maxa = 'A'; 
my $maxr = 0; 

<>; 

while (<>) { 
    chomp; 
    my ($a,$b,$c) = split /\|/; 
    $table{$a}->{$b} = $c; 

    $maxr = $a if ($a > $maxr); 
    $maxa = $b if ($b gt $maxa); 
} 

for (my $c = 'A' ; $c lt $maxa ; $c++) { 
    print $c . '|'; 
} 
print "$maxa\n"; 

for (my $r = 1 ; $r <= $maxr ; $r++) { 
    for (my $c = 'A' ; $c lt $maxa ; $c++) { 
     print $table{$r}->{$c} . '|'; 
    } 
    print $table{$r}->{$maxa} . "\n"; 
} 
+0

Wow! Быстрый ответ! Пересмотрите его сейчас ... – Josh

+0

Работает очень хорошо и быстро. Тем не менее, я просто оказываюсь с помощью awk-скрипта, поэтому я заканчиваю использование реализации ghoti. Ура! Josh – Josh

1

Если вы знаете Awk, я рекомендую вам посмотреть на Perl. Perl намного эффективнее, чем Awk. Преимущество в том, что если вы знаете оболочку BASH/Bourne и Awk, большая часть синтаксиса в Perl будет знакома.

Еще одна приятная вещь в Perl - это весь репозиторий CPAN, который позволяет вам загружать уже написанные модули Perl для использования в вашей программе. Быстрый поиск в CPAN поднял Data::Pivot, который выглядит (очень быстрый взгляд), он может делать то, что вы хотите.

Если нет, взгляните на команду Acme::Tools pivot. Или попробуйте один из many others.

Другие уже предоставили несколько решений, но я рекомендую вам посмотреть, что такое архив CPAN Perl. Это очень мощный инструмент для подобных вещей.

+0

Мне определенно нужно узнать больше Perl ..... Спасибо за ссылки! мистифицировать – Josh