Awk вычитание записей

#awk

#awk

Вопрос:

у меня есть набор данных, который похож на следующий, однако намного больше:

 5 6 9
2 4 6
4 5 1
 

Я хочу иметь возможность вычитать каждое поле в каждой записи из текущего, затем сложить их вместе и сохранить результаты. Например, здесь я хотел бы, начиная с первой строки (5-2) (6-4) (9-6) = результат. А также (5-4) (6-5) и (9-1). Также сделайте это для всех других строк, например, для второй строки (2-4) (4-5) (6-1) и (2-5) (4-6) (6-9) и т.д. Я могу сделать это вручную следующим образом:

 {
     if (max_nf < NF)
          max_nf = NF
     max_nr = NR
     for (x = 1; x <= NF; x  )
          vector[x, NR] = $x
}

END { result = ((vector[1,1] - vector[1,2])   (vector[2,1] - vector[2,2])   (vector[3,1] - vector[3,2]))
}
 

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

Комментарии:

1. И что вы хотите сделать с результатом? Распечатать все значения?

Ответ №1:

Одной из очевидных возможностей было бы что-то в этом порядке:

 BEGIN { getline; fields = NF 1; for (i=1; i<fields; i  ) first[i] = $i; }

    { 
      total = 0;
      for (field = 1; field < fields; field  )  
          total  = first[field] - $field;
      printf("%dn", total);
    }
 

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

Редактировать (чтобы соответствовать отредактированному вопросу):

Учитывая, что вы изменили вопрос, чтобы задать, вам, очевидно, нужно прочитать все данные в массив, затем пройти по массиву и сложить различия между записями. Это больше не очень хорошо согласуется с тем, как работает awk, поэтому моим непосредственным советом было бы использовать что-то другое. Если вы все равно настаиваете на использовании awk, вы могли бы в принципе поместить всю обработку в BEGIN блок, считывая все строки в большой массив, затем просматривая его, выполняя все вычисления, а затем распечатывая результаты.

Комментарии:

1. Как мне изменить это, чтобы оно делало то же самое в следующих строках?

Ответ №2:

 awk '
  BEGIN { getline; split($0,v1) }
  { 
    split($0,v2); 
    result=0; 
    for (i in v1) { 
      result  = v1[i]-v2[i];
    }
    print result
  }
'
 

Ответ №3:

Обратите внимание, что когда-либо используются только суммы записей. Таким образом, вы можете упростить задачу, рассматривая ее как два шага:

  1. Найдите общее количество для каждой записи.
  2. Вычислите различия итогов.

Это может выглядеть так:

 cat data | # generate the data in whatever fashion
  awk '{ for (n=1; n<=NF; n  ) 
           recsum[NR] =$n
       } 
       END { 
         for (n=1; n<=NR; n  ) 
           for (m=n 1; m<=NR; m  ) 
             print n, m, recsum[n]-recsum[m] }'
 

Для образца данных, приведенных в вопросе, это дает ожидаемые результаты:

 1 2 8
1 3 10
2 3 2