Найти максимум всех столбцов на основе отличия первого столбца

Вам следует использовать PinguyBuilder

PinguyBuilder - это скрипт, который позволяет создавать индивидуальный Live CD / Live USB (remaster) Ubuntu или Linux Mint, который можно использовать либо как распространяемый ISO, либо как резервная копия.

2
06.07.2017, 00:32
6 ответов

awkрешение длялюбоеколичество столбцов (вы упомянули образец файла с 13 столбцами):

Допустим, у нас есть файл расширенного примера:

1   10  15  10  99
3   34  20  20  111
1   4   22  22  33
3   32  33  12  5
5   3   46  44  9
2   2   98  55  55 
4   20  100 11  33
3   13  23  77  23
4   50  65  33  66
1   40  76  78  16
2   20  22  98  93

awk '{ for(i=2;i<=NF;i++) { if (!($1 in a) || $i > a[$1][i]) a[$1][i]=$i }}
     END{ r=""; for(i in a) { r=i; for(j in a[i]) r=r OFS a[i][j]; print r } 
     }' OFS='\t' file

Выход:

1   40  76  78  99
2   20  98  98  93
3   34  33  77  111
4   50  100 33  66
5   3   46  44  9
4
27.01.2020, 21:48

Вот один из способов в awk:

$ awk '{ 
        if($2 > a[$1][2]){
            a[$1][2] = $2
        } 
        if($3 > a[$1][3]){
            a[$1][3] = $3
        }
       }
  END{
        for(i in a){
            printf "%s ", i; 
            for(c=1; c<=maxFields; c++){
              if(c in a[i]){
                 printf "%s ",a[i][c]
              }
            }
            print ""
        }' ifile.dat 
1 40 76
2 20 98
3 34 33
4 50 100
5 3 46

Сценарий просто использует двухмерный -массив aдля хранения максимального значения для каждого из двух столбцов. Для каждого значения i1-го столбца a[i][2]будет содержать максимальное значение, найденное для iво 2-м столбце, и a[i][3]максимальное значение для 3-го столбца. После обработки всего файла мы печатаем максимальные значения для каждого значения i.


Если у вас более 3 столбцов, вы можете использовать:

awk '{ 
        for(c=2; c<=NF; c++){
            if($c > a[$1][c]){
                a[$1][c] = $c; 
            }
        }
       } 
       END{
            for(i in a){
                printf "%s: ", i; 
                for(c in a[i]){
                    printf "%s ",a[i][c]
                }
                print ""
            }
        }' ifile.dat 

Обратите внимание, что приведенное выше решение не будет работать корректно с отрицательными значениями или если у вас может быть 0и т. д., и оно может привести к неправильному порядку полей, поскольку awkне обязательно обходит массивы по порядку. Более надежный подход:

awk '{ 
        for(c=2; c<=NF; c++){
            if(!(c in a) || $c > a[$1][c]){
                a[$1][c] = $c; 
            }
        }
      } 
      END{
            for(i in a){
                printf "%s ", i; 
                for(c in a[i]){
                    printf "%s ",a[i][c]
                }
                print ""
            }
         }' ifile.dat 
4
27.01.2020, 21:48

Datamash GNU отлично подходит для подобных вещей:

$ datamash -sW groupby 1 max 2,3 < ifile.dat 
1   40  76
2   20  98
3   34  33
4   50  100
5   3   46

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

datamash -sW groupby 1 max 2-13 < ifile.dat 
7
27.01.2020, 21:48

Использование сортировки в качестве основного инструмента:

sort             ifile.dat -k1,1 -k2,2nr | sort -uk1,1 | awk '{print $1,$2}' \
| paste - <(sort ifile.dat -k1,1 -k3,3nr | sort -uk1,1 | awk '{print $3}')
2
27.01.2020, 21:48

Скрипт Python 3

#!/usr/bin/env python3
import sys
from collections import OrderedDict as od

# read data in the file first, create data dictionary of column lists
data = od()
with open(sys.argv[1]) as f:
     for line in f:
          columns = line.strip().split()
          how_many = len(columns)-1
          if columns[0] not in data.keys():
              data[ columns[0] ] = [ [] for i in range(how_many) ]
          for index in range(how_many):
              data[ columns[0] ][index].append( int(columns[index+1]) )

# post process all the created lists of lists by applying max() on each
for item in sorted(data.keys()):
    print(item,end=" ") 
    for array in data[item]:
        print(max(array),end=" ")
    print("")

Пробный запуск

С примером ввода, предоставленным OP:

$./columns_max.py input.txt                                                                                                                         
1 40 76 
2 20 98 
3 34 33 
4 50 100 
5 3 46 

С расширенным примером в ответе Романа Перехреста:

$./columns_max.py input.txt                                                                                                                         
1 40 76 78 99 
2 20 98 98 93 
3 34 33 77 111 
4 50 100 33 66 
5 3 46 44 9 

Как это работает:

Основная идея состоит в том, что мы создаем словарь из элементов первого столбца. Таким образом, в словаре у нас будут ключи 1,2,3,4 и 5. Каждое соответствующее значение для элемента словаря представляет собой список списков, где каждому под-списку соответствует столбец. Итак, для ключа 1 у нас будет список с двумя списками, где первый список предназначен для всех элементов столбца 2, а второй список — для всех элементов столбца 3. В основном это:

('1', [ ['10', '4', '40'], ['15', '22', '76']] )

Есть очень хорошая функция max(), которая позволяет нам взять числовой список и извлечь из него самый большой элемент. Все, что нам нужно сделать, это перебрать каждый ключ, удалить все списки и применить к ним функцию max().

2
27.01.2020, 21:48
perl -lane '
   $F[$_] > $A[$F[0]-1][$_] and $A[$F[0]-1][$_] = $F[$_] for 1.. $#F}{
   print 1+$_, "@{$A[$_]}" for grep defined $A[$_], 0.. $#A
' ifile.dat

Результаты

1 40 76
2 20 98
3 34 33
4 50 100
5 3 46

Рабочий

Data structure involved is an `LoL` (list of lists) assuming that the
column 1 data is nonnegative.

@A = (
   [column_2_max_for_idx1, column_3_max_for_idx1, column_4_max_for_idx1,...],
   [........],
);
2
27.01.2020, 21:48

Теги

Похожие вопросы