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

#awk

#авк #awk

Вопрос:

У меня есть текстовый файл с 5 столбцами, которые сгруппированы по содержимому первого столбца. Входные данные выглядят следующим образом:

 apple   1   1   1   1 
apple   2   1   2   2
apple   4   1   4   4.2
apple   4   1   4   4.5
apple   1   1   1   4.7 
apple   2   1   2   5
apple   3   1   3   6
apple   4   1   4   6.5
apple   1   1   1   6.8 
apple   2   1   2   7
apple   3   1   3   8
apple   4   1   4   8.5
apple   3   1   3   9
apple   4   1   4   10  
banana  25  4   4   1   
banana  35  10  14  1.9
banana  36  10  24  2.5
banana  37  10  34  2.6   
banana  35  10  14  4
banana  36  10  24  5.5
banana  37  10  34  5.8
banana  25  4   4   7.3   
banana  35  10  14  7.5
banana  36  10  24  8
banana  37  10  34  9
banana  37  10  34  10
  

Для каждой группы в столбце 1 я хотел бы получить только строки со значениями в последнем столбце, которые наиболее близки к числам от 1 до 10.

Например, первой строкой, выбранной для apple, будет строка, в которой значение в столбце 5 ближе всего к 1. Второй выбранной строкой будет та, в которой столбец 5 ближе всего к 2, и так далее до 10. Таким образом, независимо от того, сколько строк для apple на входе, конечный результат будет иметь 10 строк. Из приведенного выше примера желаемый результат будет выглядеть следующим образом:

 apple   1   1   1   1 
apple   2   1   2   2
apple   2   1   2   2
apple   4   1   4   4.2 
apple   2   1   2   5
apple   3   1   3   6
apple   2   1   2   7
apple   3   1   3   8
apple   3   1   3   9
apple   4   1   4   10  
banana  25  4   4   1   
banana  35  10  14  1.9
banana  37  10  34  2.6   
banana  35  10  14  4
banana  36  10  24  5.5
banana  37  10  34  5.8
banana  25  4   4   7.3   
banana  36  10  24  8
banana  37  10  34  9
banana  37  10  34  10
  

Я попробовал несколько вариантов чего-то подобного, что помогло мне частично продвинуться туда, но я не знаю, как выполнить итерацию на основе категорий в первом столбце.

 awk '{for (i=1; i<=10; i  ) BEGIN{a=100} {aa=i-$5;if (aa<a amp;amp; aa>0) {a=aa;n=$0}} END {print n}}' fruit.txt

  

Спасибо за любые предложения — я учусь по ходу дела, поэтому пояснения или советы по синтаксису всегда очень ценятся!

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

1. Спасибо, что продемонстрировали свои усилия в виде кода в вашем вопросе, продолжайте в том же духе. Переходя к логике получения ожидаемого результата, не могли бы вы подробнее остановиться на логической части для получения ожидаемого результата, поскольку неясно, на каком основании вы хотите игнорировать строки.

2. Привет @RavinderSingh13! Вы вернулись, чтобы снова мне помочь — большое вам спасибо! Я действительно ценю вашу помощь. Я попытался добавить еще несколько пояснений. Я в основном хочу извлечь строки, где значения последнего столбца ближе всего к числам от 1 до 10, так что у меня всегда будет 10 строк на фрукт, независимо от того, сколько строк было на входе. Я надеюсь, что это имеет хотя бы немного смысла!

3. Я понял основную мысль из этого, я считаю, что ваша banana фруктовая 2-я строка должна иметь 2.5 , а не 1.9 правильно? Пожалуйста, подтвердите меня один раз, в любом случае я добавил ответ и здесь, мы могли бы обсудить там, приветствия.

4. если у вас есть одна строка в файле, apple 1 1 1 1 ожидаете ли вы 10 x apple 1 1 1 1 на выходе?

5. Да, это совершенно верно @perreal! Поэтому при сравнении 1 с числами через 1-10 это всегда будет ближайшее число, если это единственная запись. Каждый фрукт должен содержать 10 строк, даже если строки повторяются, чтобы получить это. Я надеюсь, что это имеет смысл!

Ответ №1:

Требуется GNU awk для массивов массивов.

 function abs(v) {return v < 0 ? -v : v}                  
                                                         
{                                                        
  for (i = 1; i <= 10; i  ) {                            
    if (a[$1][i] == "" || abs(i - $5) < a[$1][i]) {      
      b[$1][i] = $0;                                     
      a[$1][i] = abs(i - $5)                             
    }                                                    
  }                                                      
}                                                        
                                                         
END {                                                    
  for (k in b) {                                         
    for (i = 1; i <= 10;   i) {                          
      print b[k][i]                                      
    }                                                    
  }                                                      
}                                                        
  

Дает:

 apple   1   1   1   1
apple   2   1   2   2
apple   3   1   3   3
apple   4   1   4   4.2
apple   2   1   2   5
apple   3   1   3   6
apple   2   1   2   7
apple   3   1   3   8
apple   3   1   3   9
apple   4   1   4   10
banana  25  4   4   1
banana  35  10  14  1.9
banana  25  4   4   3
banana  35  10  14  4
banana  36  10  24  5
banana  37  10  34  6
banana  25  4   4   7.3
banana  36  10  24  8
banana  37  10  34  9
banana  37  10  34  10