Вычислить расстояния непрерывной точки

#awk

#awk

Вопрос:

Мне нужна помощь! У меня есть несколько точек ABCDEF … с такими позициями:

 A  0.00  0.50  0.10
B  1.00  2.50  2.00
C  0.70  0.88  1.29
D  2.13  2.90  0.11
E  1.99  0.77  0.69
...
  

Я стремлюсь вычислить расстояние AB, BC, CD, EF, … и их сумму с выводом, который имеет вид, подобный этому:

 sum_distance(AB)
sum_distance(AB BC)
sum_distance(AB BC CD)
sum_distance(AB BC CD DE)
sum_distance(AB BC CD DE EF)
.... 
  

Я нашел в Интернете awk, который может это сделать и применить к моему случаю. Однако результат или ошибка не были экспортированы на экран. Не могли бы вы, пожалуйста, помочь мне с этой ситуацией?

оболочка bash, awk

 awk 'FNR==NR { a[NR]=$0; next } { for (i=FNR 1;i<=NR-1;i  ) {split(a[i],b); print $1 "-" b[1], sqrt(($2-b[2])^2   ($3-b[3])^2   ($4-b[4])^2) | "column -t" } NR--}'
  

Вывод:

 2.934280150
4.728297987
7.470140434
9.682130488
11.92469598
......
  

Ответ №1:

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

 awk 'NR>1{ printf "%.9fn",s =sqrt(($2-x)^2 ($3-y)^2 ($4-z)^2) }
{ x=$2;y=$3;z=$4 }' file
  

Для всех точек, кроме A , вычислите расстояние, добавьте его к сумме s и выведите сумму. Для всех точек сохраните координаты в x, y, z для следующего вычисления. Его вывод выглядит следующим образом с помощью gawk:

 2.934280150
4.728297987
7.470140434
9.682130488
  

Ответ №2:

Каково основное правило? (никогда не используйте код из Интернета, который вы не понимаете …)

Проблема со awk скриптом, который вы пытаетесь использовать, заключается в том, что это не совсем ваш случай. Путем установки FNR==NR , а затем использования ограничений цикла (i=FNR 1;i<=NR-1;i ) ожидается, что будет несколько входных файлов. В вашем случае вы действительно можете упростить сценарий, полностью удалив цикл, поскольку у вас есть только один входной файл.

Вам нужно только сохранить первую строку, затем с помощью next чтения следующей строки вычислить и вывести расстояние между предыдущей строкой и текущей, установить текущую строку в качестве строки в a[] массиве и повторять, пока у вас не закончатся строки, например

 awk '{
    a[NR]=$0
    if (NR == 1)
        next
    split(a[NR-1],b)
    printf "%st%sn", b[1] "-" $1, 
        sqrt(($2-b[2])^2   ($3-b[3])^2   ($4-b[4])^2)
    a[NR]=$0
}'
  

Пример входного файла

 $ cat f
A  0.00  0.50  0.10
B  1.00  2.50  2.00
C  0.70  0.88  1.29
D  2.13  2.90  0.11
E  1.99  0.77  0.69
  

Пример использования / вывода

Просто вставьте скрипт в терминал, добавив имя файла в конце, например

 $ awk '{
>     a[NR]=$0
>     if (NR == 1)
>         next
>     split(a[NR-1],b)
>     printf "%st%sn", b[1] "-" $1,
>         sqrt(($2-b[2])^2   ($3-b[3])^2   ($4-b[4])^2)
>     a[NR]=$0
> }' f
A-B     2.93428
B-C     1.79402
C-D     2.74184
D-E     2.21199
  

Просмотрите все и дайте мне знать, если у вас возникнут дополнительные вопросы.

Ответ №3:

Попробуйте это:

 awk 'function d(a,b){split(a,x);split(b,y);return sqrt((x[2]-y[2])^2   (x[3]-y[3])^2   (x[4]-y[4])^2);} {p[FNR]=$0} FNR>1{sum[FNR]=sum[FNR-1] d(p[FNR-1],p[FNR]);printf "%.9fn",sum[FNR];}' file
  

С file таким контентом , как этот:

 A  0.00  0.50  0.10
B  1.00  2.50  2.00
C  0.70  0.88  1.29
D  2.13  2.90  0.11
E  1.99  0.77  0.69
  

обеспечит вывод, подобный этому:

 2.934280150
4.728297987
7.470140434
9.682130488
  

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

Поместить в несколько строк здесь:

 awk '
function d(a,b){
    split(a,x);
    split(b,y);
    return sqrt((x[2]-y[2])^2   (x[3]-y[3])^2   (x[4]-y[4])^2);
} 
{p[FNR]=$0} 
FNR>1{
    sum[FNR]=sum[FNR-1] d(p[FNR-1],p[FNR]);
    printf "%.9fn",sum[FNR];
}' file
  

Здесь все довольно просто, функция d для расстояния. И повторно использовать сумму предыдущей строки.

И для развлечения, если вы хотите вычислить общее расстояние графика, изначально с одной точкой и постепенно добавлять точки на график. Т.Е. :

 sum_distance(AB)
sum_distance(AB BC AC)
sum_distance(AB BC AC AD BD CD)
...
  

Тогда будет достаточно небольшого улучшения, например:

 $ awk 'function d(a,b){split(a,x);split(b,y);return sqrt((x[2]-y[2])^2   (x[3]-y[3])^2   (x[4]-y[4])^2);} {p[FNR]=$0} FNR>1{sum[FNR]=sum[FNR-1];for(i=FNR-1;i>0;i--)sum[FNR] =d(p[i],p[FNR]);printf "%.9fn",sum[FNR];}' file
2.934280150
6.160254691
14.349070561
22.466306583