#awk
#awk
Вопрос:
Хотелось бы рассчитать вычисление сляба на основе информации StartRange, endRange, Category и Flag_value.
SampleInput.txt
Field1,Field2,Field3,Field4,Field5,Field6
Desc,Name,Category,Desc2,Flag_Value,Slab_Count
ZZZ,ABC,A,xyz,2,140
ZZZ,CDE,A,xyz,-5,140
ZZZ,FGH,B,xyz,10,48
ZZZ,IJK,B,xyz,-10,48
ZZZ,LMN,C,xyz,115,248
ZZZ,OPQ,A,ijk,-62,250
ZZZ,RST,D,ijk,67,350
ZZZ,UVW,A,ijk,-80,5
ZZZ,XYZ,A,ijk,48,6
Slab.txt
StartRange,EndRange,Category-A,Category-B,Category-C,Category-D,Flag_Value
1,50,350,350,500,500,-125
51,100,450,500,550,600,-150
101,150,600,600,600,650,-150
151,200,700,650,650,650,-200
201,250,800,750,700,700,-250
251,1000,900,850,800,800,-300
Метод для вычисления первой строки SampleInput.txt , необходимо принять входные данные от SampleInput.txt Field3 (т.е. A), Field5>0 (т.е. 2) и Field6 (т.е. 140)
затем выполняют поиск данных из Slab.txt чтобы найти диапазон лежания (т.е. 101,150,600,600,600,650, -150), категория(т.е. Категория-A) и выведите соответствующее значение, например 600
Вторая строка SampleInput.txt , необходимо принять входные данные от SampleInput.txt Field3 (т.е. A), Field5<0 (т.е. -5) и Field6 (т.е. 140) затем выполняют поиск данных из Slab.txt чтобы найти диапазон лежания (например, 101,150,600,600,600,650, -150), категория (i.Категория e-A) и выведите соответствующее значение дополнительной категории-A Flag_Value, т.е. 450 (600-150)
Ожидаемый Output.txt
Desc,Name,Category,Desc2,Flag_Value,Slab_Count,Slab_Amt
ZZZ,ABC,A,xyz,2,140,600
ZZZ,CDE,A,xyz,-5,140,450
ZZZ,FGH,B,xyz,10,48,350
ZZZ,IJK,B,xyz,-10,48,225
ZZZ,LMN,C,xyz,115,248,700
ZZZ,OPQ,A,ijk,-62,250,550
ZZZ,RST,D,ijk,67,350,800
ZZZ,UVW,A,ijk,-80,5,225
ZZZ,XYZ,A,ijk,48,6,350
много искал в Google, чтобы найти соответствующие попытки, и не смог найти то же самое, застрял, чтобы найти на сложном уровне, ищу ваши предложения.
Ответ №1:
Вот еще одна возможность:
awk '
BEGIN { FS = OFS = "," }
NR == 1 { next }
FNR == 1 { print $0, "Slab_Amt" }
NR == FNR {
range[$1,$2,"A"] = $3
range[$1,$2,"B"] = $4
range[$1,$2,"C"] = $5
range[$1,$2,"D"] = $6
flag[$1,$2] = $NF
next
}
{
for (key in range) {
split (key, tmp, SUBSEP);
if (tmp[3] == $3 amp;amp; tmp[1] <= $NF amp;amp; $NF <= tmp[2]) {
value = ( $5 > 0 ? range[key] : range[key] flag[tmp[1],tmp[2]] )
print $0, value
next
}
}
}' Slab.txt SampleInput.txt
Вывод:
Desc,Name,Category,Desc2,Flag_Value,Slab_Count,Slab_Amt
ZZZ,ABC,A,xyz,2,140,600
ZZZ,CDE,A,xyz,-5,140,450
ZZZ,FGH,B,xyz,10,48,350
ZZZ,IJK,B,xyz,-10,48,225
ZZZ,LMN,C,xyz,115,248,700
ZZZ,OPQ,A,ijk,-62,250,550
ZZZ,RST,D,ijk,67,350,800
ZZZ,UVW,A,ijk,-80,5,225
ZZZ,XYZ,A,ijk,48,6,350
Объяснение:
- Мы устанавливаем разделители полей ввода и вывода на
,
использованиеBEGIN { FS = OFS = "," }
- Если это первая строка первого файла, мы пропускаем ее, используя
NR == 1 { next }
- Для первой строки нашего второго файла мы печатаем добавление заголовка
Slab_Amt
as с помощьюFNR == 1 { print $0, "Slab_Amt" }
- Мы перебираем
Slab.txt
файл, хранящий значения каждой категории в нашем многомерном массиве, имеющем начальный диапазон, конечный диапазон и категорию в качестве ключей вrange
массиве. - Мы сохраняем значение флага в
flag
массиве с ключом в начальном и конечном диапазонах. - Когда мы начинаем обрабатывать
SampleInput.txt
файл, мы повторяем наш массив диапазонов и разделяем ключ. - Мы проверяем, равна ли третья часть нашего ключа 3-му столбцу выборки входных данных, а последний столбец находится между нашими диапазонами. Если это так, мы вычисляем значение, проверяя, больше ли 5-й столбец 0. Если это так, мы просто присваиваем значение нашего диапазона, если нет, мы добавляем значение диапазона к значению флага и печатаем строку вместе с нашим значением.
- Используя
next
, мы пропускаем дальнейшие проверки и переходим к следующей строке ввода образца.
Комментарии:
1. Большое спасибо, Jaypal, все работает нормально, не могли бы вы дать некоторые пояснения, чтобы понять код
2. @AVN добавили объяснение. Надеюсь, это поможет.
3. @AVN В дополнение к объяснению jaypal вам необходимо прочитать руководство gnu awk (или какое-либо другое руководство / книгу), чтобы выучить язык.
Ответ №2:
Вот такая возможность.
awk -F, '
BEGIN {
getline <"Slab.txt" # skip header
while ((getline <"Slab.txt") > 0)
slabs[int($2)] = $0
# Last index must be greater than top of range
slabs[999999] = "endmarker"
}
NR == 2 { print $0",Slab_Amt" }
NR > 2 {
n = int($6)
for (rangetop in slabs)
if (n <= int(rangetop))
break
if (rangetop == 999999) {
print "n out of range:",n >"/dev/stderr"
exit(1)
}
split(slabs[rangetop], fields, ",")
switch ($3) {
case "A": val = fields[3]; break
case "B": val = fields[4]; break
case "C": val = fields[5]; break
case "D": val = fields[6]; break
default:
print "unknown category:",$3 >"/dev/stderr"
exit(1)
}
if ($5 < 0)
val = fields[7]
print $0","val
}
' SampleInput.txt
Комментарии:
1. Большое спасибо @ ooga за ваши данные, но, похоже, неверный вывод, Desc, Name, Category, Desc2, Flag_Value, Slab_Count, ZZZ, ABC, A, xyz,2,140,800 ZZZ, CDE,A, xyz, -5,140,550
2. ожидаемый результат Desc, Name,Category, Desc2,Flag_Value, Slab_Count,Slab_Amt ZZZ,ABC,A,xyz,2,140,600 ZZZ,CDE,A,xyz,-5,140,450
3. Вероятно, это потому, что я предполагал, что заголовков на самом деле не было в файлах данных. Я отредактирую его, но в любом случае я предпочитаю ответ джейпала.