У меня есть 2 файла данных: file01
и file02
. В обоих наборах полей данных: (i) идентификатор; (ii) числовая ссылка; (iii) долгота; и (iv) широта. Для каждой строки в file01
я хочу найти данные в file02
с той же числовой ссылкой, а затем найти идентификатор в file02
, который является ближайшим к идентификатору в file01
.Слияние двух наборов данных с использованием AWK
я могу получить это, если я прохожу вручную значение от file01
к программе AWK, используя следующий код:
awk 'function acos(x) { return atan2(sqrt(1-x*x), x) }
BEGIN {pi=3.14159;
ndist=999999999.1;
date=1001;
lo1=-1.20; lg1=lo1*(pi/180);
la1=30.31; lt1=la1*(pi/180)
}
{if($2==date) {ws=$1;
lg2=$3*(pi/180);
lt2=$4*(pi/180);
dist= 6378.7 * acos(sin(lt1)*sin(lt2) + cos(lt1)*cos(lt2)*cos(lg2-lg1));
if(dist < ndist) {ndist=dist; ws0=ws}}}
END {print(ws0,ndist)}' file02
Как вы видите, date
, lo1
и la1
в BEGIN
заявления являются значением в 1-я строка file01
(см. Ниже для файлов данных). Мой вопрос в том, могу ли я сделать это сразу, поэтому каждый раз, когда я читаю строку в file01
, я получаю ближайший идентификатор и расстояние и добавляю к данным строки в file01
. Я не знаю, может ли какая-нибудь команда оболочки выполнить это проще, возможно, используя канал.
Пример этих двух файлов данных и желаемого выхода являются:
=== file01 ===
A 1001 -1.2 30.31
A 1002 -1.2 30.31
B 1002 -1.8 30.82
B 1003 -1.8 30.82
C 1001 -2.1 28.55
=== file02 ===
ws1 1000 -1.3 29.01
ws1 1001 -1.3 29.01
ws1 1002 -1.3 29.01
ws1 1003 -1.3 29.01
ws1 1004 -1.3 29.01
ws1 1005 -1.3 29.01
ws2 1000 -1.5 30.12
ws2 1002 -1.5 30.12
ws2 1003 -1.5 30.12
ws2 1004 -1.5 30.12
ws2 1005 -1.5 30.12
ws3 1000 -1.7 29.55
ws3 1001 -1.7 29.55
ws3 1002 -1.7 29.55
ws3 1003 -1.7 29.55
ws3 1004 -1.7 29.55
ws3 1005 -1.7 29.55
ws4 1000 -1.9 30.33
ws4 1001 -1.9 30.33
ws4 1002 -1.9 30.33
ws4 1003 -1.9 30.33
ws4 1004 -1.9 30.33
ws4 1005 -1.9 30.33
= == выходной файл ===
A 1001 -1.2 30.31 ws4 67.308
A 1002 -1.2 30.31 ws2 35.783
B 1002 -1.8 30.82 ws4 55.387
B 1003 -1.8 30.82 ws4 55.387
C 1001 -2.1 28.55 ws1 85.369
EDIT # 1: Учитывая предложение по @Eran, я написал следующий код:
join -j 2 < (sort -k 2,2 file01) < (sort -k 2,2 file02) |
awk 'function acos(x) { return atan2(sqrt(1-x*x), x) }
BEGIN {pi=3.14159}
{if (last != $1 $2)
{print NR, id,r,lon,lat,ws0,ndist;
last = $1 $2;
ndist=999999999.1
} else {
lg1=$3*(pi/180);
lt1=$4*(pi/180);
lg2=$6*(pi/180);
lt2=$7*(pi/180);
dist= 6378.7 * acos(sin(lt1)*sin(lt2) + cos(lt1)*cos(lt2)*cos(lg2-lg1));
if(dist< ndist) {ndist=dist; ws0=$5}
id=$2;r=$1;lon=$3;lat=$4
}
}'
Выход из этого сценария является:
1
4 A 1001 -1.2 30.31 ws4 67.3078
7 C 1001 -2.0 28.55 ws3 115.094
11 A 1002 -1.2 30.31 ws2 35.7827
15 B 1002 -1.8 30.82 ws4 55.387
EDIT # 2: Используя следующее å предложение @Dennis (с некоторыми изменениями) У меня есть желаемый результат. Сценарий awk выглядит следующим образом:
awk 'function acos(x) { return atan2(sqrt(1-x*x), x) }
BEGIN {pi=3.14159}
NR==FNR {c++; a1[c]=$1;a2[c]=$2;a3[c]=$3;a4[c]=$4; next}
{d++; b1[d]=$1;b2[d]=$2;b3[d]=$3;b4[d]=$4}
END {
for(k=1;k<=c;k++) {
lg1=a3[k]*(pi/180);
lt1=a4[k]*(pi/180);
ndist=999999999.1;
for(l=1;l<=d;l++) {
if(b2[l]==a2[k]) {kk=b2[l];
lg2=b3[l]*(pi/180);
lt2=b4[l]*(pi/180);
dist= 6378.7 * acos(sin(lt1)*sin(lt2) + cos(lt1)*cos(lt2)*cos(lg2-lg1));
if(dist<ndist) {ndist=dist; ws0=b1[l]}
}
}
print a1[k],a2[k],a3[k],a4[k],ws0,ndist
}
}' file01 file02
+1 Благодарим вас @ Dennis, ваш ответ был очень полезен! –