2014-01-30 6 views
2

Файл:AWK с повторяющимися значениями

22 Hello 
22 Hi 
1 What 
34 Where 
21 is 
44 How 
44 are 
44 you 

Желаемая Выход:

22 HelloHi 
1 What 
34 Where 
21 is 
44 Howareyou 

Если есть повторяющиеся значения в первом поле ($ 1) второе поле должно быть прилагаемая текст

Как достичь этого с помощью awk?

Благодаря

+0

Я думаю, что это будет * путь * проще для использования, например, Python для этого. Вы уверены, что собираетесь использовать awk? –

+0

Да, я определенно ищу решение awk – user1502952

+0

@ UliKöhler: ты шутишь !? :-) С нетерпением жду ответа на Python. Я буду голосовать за любой рабочий ответ, который вы хотите опубликовать. Всем удачи. – shellter

ответ

6

Использование AWK:

awk '!($1 in a){a[$1]=$2;next} $1 in a{a[$1]=a[$1] $2} END{for (i in a) print i, a[i]}' file 
22 HelloHi 
44 Howareyou 
34 Where 
21 is 
1 What 

EDIT: Чтобы сохранить порядок:

awk '!($1 in a){b[++n]=$1; a[$1]=$2;next} $1 in a{a[$1] = a[$1] $2} 
     END{for (i=1; i<=n; i++) print b[i], a[b[i]]}' file 
22 HelloHi 
1 What 
34 Where 
21 is 
44 Howareyou 
+0

Спасибо, возможно ли, что решение находится в том же порядке, что и в файле – user1502952

+0

, порядок в желаемом выходе – user1502952

+0

см. Отредактированный код для поддержания заказа. – anubhava

10
$ awk ' 
!seen[$1]++ { keys[++numKeys] = $1 } 
{ str[$1] = str[$1] $2 } 
END{ 
    for (keyNr=1; keyNr<=numKeys; keyNr++) { 
     key = keys[keyNr] 
     print key, str[key] 
    } 
} 
' file 
22 HelloHi 
1 What 
34 Where 
21 is 
44 Howareyou 
+0

+1, это хорошо. почти так же, как моя :) спасибо. – Endoro

1

Вот альтернативное решение в Python, в соответствии с просьбой @ раковина:

from collections import defaultdict 

with open("file") as infile: 
    d = defaultdict(str) 
    #Build dictionary of values 
    for line in infile: 
     line = line.strip() 
     k, _, v = line.partition(" ") 
     d[k] += v 
    #Print everything 
    for k, v in d.iteritems(): 
     print k,v 

Обратите внимание, что заказ не сохраняется в этом решении. Вот альтернативное решение, которое обеспечивает точно желаемый результат:

from collections import defaultdict 

with open("file") as infile: 
    d = defaultdict(str) 
    orig_order = [] 
    #Build dictionary of values 
    for line in infile: 
     line = line.strip() 
     k, _, v = line.partition(" ") 
     d[k] += v 
     #Add to original order if not seen yet 
     if not k in orig_order: 
      orig_order.append(k) 
    #Print everything 
    for k in orig_order: 
     print k, d[k] 

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

+1

Ты должен мужчине :) @shellter – zee

+1

+1, .... но .... 'Я думаю, что будет проще использовать, например. Python для этого », ... ну ... я думаю, это зависит от вашей перспективы. Удовольствие, чтобы прочитать и получить представление об основной обработке python txt. Спасибо, что поделился! – shellter

+0

@shellter Он делает ;-) взял меня около 45 секунд для не заказанной версии, плюс примерно то же для заказанной версии. Используя понимание list/dict, я предполагаю, что можно уменьшить размер на ~ 80%. Я думаю, что основное преимущество здесь в том, что его можно использовать повторно в более крупном приложении. Но я должен отметить, что я вообще не в * awk *, что, безусловно, влияет на мою перспективу. –

5

Для поддержания порядка, вам нужно следить за ним:

awk ' 
    ! seen[$1]++ {order[++n] = $1} 
    {value[$1] = value[$1] $2} 
    END {for (i=1; i<=n; i++) print order[i], value[order[i]]} 
' <<END 
22 Hello 
22 Hi 
1 What 
34 Where 
21 is 
44 How 
44 are 
44 you 
END 
22 HelloHi 
1 What 
34 Where 
21 is 
44 Howareyou 

Если вы знаете значения в 1-м столбце являются смежными, так как в тексте образца, а затем:

awk ' 
    prev != $1 {printf "%s%s ", sep, $1; sep=RS} 
    {printf "%s", $2; prev = $1} 
    END {print ""} 
' 

несколько других подходов:

perl -lane ' 
     push @keys, $F[0] unless grep {$_ eq $F[0]} @keys; 
     $val{$F[0]} .= $F[1] 
    } END { 
     print "$_ $val{$_}" for @keys 
' file 

и, достигая путь в нишу зоны

#!/usr/bin/env tclsh 
while {[gets stdin line] != -1} {dict append val {*}$line} 
dict for {k v} $val {puts "$k $v"} 
0

если порядок не имеет значения, это будет работать:

awk '{a[$1]=a[$1]$2}; END {for (i in a) {print a[i]}}' file 

.. и если заказ является важно:

awk '{if (!a[$1]) b[++i]=$1;a[$1]=a[$1]$2}; END {for (j=1;j<i;j++) {print a[b[j]]}}' file 
Смежные вопросы