Один из возможных ответов с использованием awk:
awk '/name: /{name=substr($0,7)} /count: /{cnt=substr($0,8)} /region:/{print name" "cnt" "substr($0,9)}' input
awk -v s=0.2 -v e=0.3 -v d=0.01 '
BEGIN { m = 1/d }
{ a[int($1*m)]++ }
END{ e *= m; for(s = int(s*m); s <= e; s++) print s*d, a[s]+0 }
' test_OH.txt
0.2 18
0.21 5
0.22 3
0.23 0
0.24 0
0.25 0
0.26 0
0.27 0
0.28 0
0.29 3
0.3 2
Переменныеs
(начало)e
(конец )иd
(дельта/шаг )можно настроить по мере необходимости.
генерация диапазона путем многократного добавления 0.01
— почти хрестоматийный пример того, что НЕ нужно делать с числами с плавающей запятой, потому что 0.01
не может быть точно представлено в системе счисления 2, и ошибка будет накапливаться с каждым добавлением.
сканирование всего диапазона для каждой строки неэффективно и бессмысленно.
переменные в awk не должны быть инициализированы как ""
или 0
.
Попробуйте это:
awk '
BEGIN {for (i=0;i<1.01;i+=0.01) a[i]=0}
{
n = int($1 * 100) / 100
a[n] += 1
}
END {for (k=0;k<1.01;k+=0.01) print k,a[k]}'
или это, что я нахожу менее понятным:
awk 'BEGIN {for (i=0;i<1.01;i+=0.01) a[i]=0} {
for (j=0;j<=1;j+=0.01)
if(("X" $1 >= "X" j) && ("X" $1 < "X" j+0.01)) {
a[j]+=1
}
}
END {for (k=0;k<1.01;k+=0.01) print k,a[k]}'
О том, почему оригинал не работал, см. замечание Квазимодо выше.
Не уверен, следует ли публиковать это как ответ или комментарий, но вот короткая демонстрация неточности и полученных в этом случае чисел на моей машине:
$ awk 'BEGIN { d = 0.01; printf "%.20f\n", d; for (i = 0; i < 30; i++) a += d; printf "%.20f\n%.20f\n", 0.3, a }'
0.01000000000000000021
0.29999999999999998890
0.30000000000000009992
Первое число — это то, как фактически сохраняется 0,01.это не точно, так как 1/100 включает коэффициент 1/5 и не может быть представлен в двоичном виде.
Второе — это то, как 0,3 сохраняется, а третье — это 0,01, добавляемое к самому себе 30 раз. (Это даже не то же самое, что 0.01 * 30
, потому что, я полагаю, на каждом шаге есть промежуточное округление.)
В других ответах есть решения, проголосуйте за них.