Как с помощью sort или awk отсортировать строки с одинаковым количеством полей, но разными значениями одного поля? - PullRequest
0 голосов
/ 14 июля 2020

Я хочу охарактеризовать строки с одинаковыми полями, но разными значениями поля в той же позиции поля, как одно и то же и выбрать только одну строку.

Пример ввода

Пусть разделитель полей будет "/"

1. abc/def/gh/ij/kl
2. abc/def/gh/ij/yi
3. abc/def/gh/ij/ti
4  abc/def/gh/hk/kl/oi/uh
5. abc/def/gh/ol/kl/oi/uh
6. abc/def/gh/er/kl/oi/uh
7. abc/def/gh/er/kl

Обрабатывать строки 1,2,3 как одинаковые и выбрать только 1 строку, даже если значения их 5-го поля различны, они имеют одинаковое значение другие поля и имеют такое же поле.

Считайте строки 4,5,6 одинаковыми и выберите из них только 1 строку, даже если значения их 4-го поля отличаются, они имеют такое же значение, что и другие поля и имеют равное поле.

Строки 6 и 7 не совпадают, так как у них разное количество полей.

Желаемый результат

abc/def/gh/ij/kl
abc/def/gh/hk/kl/oi/uh

ПРИМЕЧАНИЕ : в списке есть строки с разными номерами полей.

Я пробовал sort -u, но это явно не сработало, поскольку сортировка не использует разделитель. Может ли awk этого добиться?

Ответы [ 4 ]

2 голосов
/ 14 июля 2020
$ awk -F'/' '!seen[NF]++' file
abc/def/gh/ij/kl
abc/def/gh/hk/kl/oi/uh

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

1 голос
/ 14 июля 2020
$ awk -F/ 'function comb(i) {k=""; 
                             for(j=1  ;j<i  ;j++) k=k FS $j; 
                             for(j=i+1;j<=NF;j++) k=k FS $j; 
                             return k}

           !a[$0] {a[$0]; 
                   for(i=1;i<=NF;i++) if(a[comb(i)]) next; 
                   print; 
                   for(i=1;i<=NF;i++) a[comb(i)]++}' file

abc/def/gh/ij/kl
abc/def/gh/hk/kl/oi/uh

в массиве ha sh проверьте все комбинации полей с отсутствующим одним полем, если не найдено, добавьте все комбинации с отсутствующим одним полем. Также добавьте полную запись для тривиальных случаев.

1 голос
/ 14 июля 2020

Учитывая ваше определение равенства в комментарии (которое действительно должно go в вопросе, а не в комментарии), вашу проблему невозможно решить по математическим причинам:

Для вас две строки равны , если они отличаются не более чем в одном поле.

Значит, для вас /a/b/c/d == /a/b/c/e, потому что они отличаются только в последнем поле. По той же причине /a/b/c/e == /a/x/c/e, потому что они тоже различаются только в одном поле (втором).

Но для того, чтобы набор был сортируемым, отношение порядка должно быть полным порядком, что означает, что равенство должен быть переходным. Т.е. для любых тройных X, Y, Z, X==Y и Y==Z должно подразумеваться , что X==Z.

Давайте установим для вашего случая

X=/a/b/c/d
Y=/a/b/c/e
Z=/a/x/c/e

Требование для totalorder требует, чтобы X==Z, т.е. /a/b/c/d == /a/x/c/e, но они различаются в двух полях, а не в одном.

1 голос
/ 14 июля 2020

На основании моего комментария, который исключает строку 7, это можно сделать в gawk:

gawk -F "/" '
   BEGIN{ a[0][0]=""; }{ if (a[$1$2$3][NF]!=null)
                {
                }
                else {
                        a[$1$2$3][NF]=$0;
                        }
        }
   END{ delete a[0][0]; 
        for(i in a){
        for(j in a[i]) {
                print a[i][j]
        }}
    }' input

output:

abc/def/gh/ij/kl
abc/def/gh/hk/kl/oi/uh

EDIT: поскольку строка 7 должна находиться в результат тоже ?:

#!/bin/bash
gawk -F "/" '
NF!=p{
   delete a[0];
   for(i in a){
        print a[i]
   }
   p=NF;
   delete a;
   a[0]="";
}
{
   if (p==0) p=NF;
   if (a[$1$2$3]==null)
   {
      a[$1$2$3]=$0;
   };
}
END {
  for (i in a) {
          print a[i];
  }
}'

вывод:

abc/def/gh/ij/kl
abc/def/gh/hk/kl/oi/uh
abc/def/gh/er/kl

(Краткое) объяснение:

NF!=p если количество полей изменилось, распечатайте результаты.

a[$1$2$3] - ключ результата (ов). Теперь я действительно вижу, что это не обязательно должен быть массив, потому что у меня только максимум 1 результат (на количество полей)

END{} распечатать последний результат.

...