Как расположить элементы по заголовку?

Как расположить элементы по заголовку?

У меня есть более 5000 строк, разделенных пробелами, как показано ниже:

Item_A: Acou#1  Bla#5

Item_B: Acou#1  Elfa#2  Flq#2

Item_C: Acou#1  Bla#4   Elfa#2  Flq#2

Item_D: Agly#3  Bla#4   Elfa#2

Я хочу создать таблицу с общими заголовками для всех и количеством для каждого элемента в таблице, как показано ниже.

             Acou  Agly  Bla  Elfa  Flq

Item_A:      1     0     5    0     0

Item_B:      1     0     0    2     2

Item_C:      1     0     4    2     2

Item_D:      0     3     4    2     0

Я использовал grep для строк, содержащих "Acou", затем "Bla" и т. д. Затем редактировал в Excel, чтобы количественно оценить их и объединить все отдельные файлы в один файл. Однако это занимало много времени.

решение1

BEGIN { OFS = "\t" }

# Collect headers from data
FNR == NR {
    for (i = 2; i <= NF; ++i)
        if (!($i in heads))
            heads[$i]
    next
}

# Output header
FNR == 1 {
    line = "Items"
    for (j in heads)
        line = line OFS j
    print line
}

{
    line = $1
    # Iterate through the header items, testing each field against it
    for (j in heads) {
        found = 0 # assume not found
        for (i = 2; !found && i <= NF; ++i)
            if ($i == j)
                found = 1 # matches header
        line = line OFS found
    }
    print line
}

Запускаем это на ваших данных (после удаления пустых строк):

$ awk -f script.awk file file
Items   Acou#1  Bla#4   Bla#5   Elfa#2  Agly#3  Flq#2
Item_A: 1       0       1       0       0       0
Item_B: 1       0       0       1       0       1
Item_C: 1       1       0       1       0       1
Item_D: 0       1       0       1       1       0

Обратите внимание, что вам нужно указать файл входных данных дважды. Это связано с тем, что мы сканируем его дважды. При первом сканировании мы собираем элементы данных в каждой строке (блок FNR == NR). При втором сканировании мы проверяем каждый собранный элемент данных (заголовки) по отношению к данным в каждой строке.

Вывод просто, 0если поле в заголовке отсутствует в данных на этой строке, и 1если оно есть. Это недовольното, о чем вы просили, так что...

Вариант, который обрезает заголовки в точке #и использует часть после #в качестве данных для отображения:

BEGIN { OFS = "\t" }

# Collect headers from data
FNR == NR {
    for (i = 2; i <= NF; ++i) {
        split($i, h, "#")
        if (!(h[1] in heads))
            heads[h[1]]
    }
    next
}

# Output header
FNR == 1 {
    line = "Items"
    for (j in heads)
        line = line OFS j
    print line
}

{
    line = $1
    # Iterate through the header items, testing each field against it
    for (j in heads) {
        found = 0 # assume not found
        for (i = 2; !found && i <= NF; ++i) {
            split($i, h, "#")
            if (h[1] == j)
                found = h[2] # matches header
        }
        line = line OFS found
    }
    print line
}

Запуск:

$ awk -f script.awk file file
Items   Elfa    Bla     Acou    Agly    Flq
Item_A: 0       5       1       0       0
Item_B: 2       0       1       0       2
Item_C: 2       4       1       0       2
Item_D: 2       4       0       3       0

Обратите внимание, что порядок столбцов не обязательно отсортирован (поскольку они хранятся как ключи в ассоциативном массиве). Я оставляю читателю в качестве упражнения сортировку.

решение2

Если вы не против броситьGNU-датамашв смесь, то вы можете просто сериализовать записи, а затем составить их перекрестную таблицу:

awk '
  {for (i=2;i<=NF;i++) {split($i,a,"#"); print $1,a[1],a[2]}}' OFS='\t' file | 
  datamash --filler=0 crosstab 1,2 count 3
    Acou    Agly    Bla Elfa    Flq
Item_A: 1   0   1   0   0
Item_B: 1   0   0   1   1
Item_C: 1   0   1   1   1
Item_D: 0   1   1   1   0

Альтернативный вариант — с помощью GNU awk (который позволяет использовать многомерные массивы):

gawk '
  BEGIN {
    OFS="\t";
    PROCINFO["sorted_in"] = "@ind_str_asc";
  }
  {
    for (i=2;i<=NF;i++) {
      split($i,a,"#"); 
      h[a[1]] = 1;
      t[$1][a[1]] += a[2];
    }
  } 
  END {
    for (j in h) printf("\t%s", j);
    printf "\n";
    for (i in t) {
      printf("%s",i);
      for (j in h) 
        printf("\t%d", j in t[i] ? t[i][j] : 0);
      printf "\n";
    }
  }' file
    Acou    Agly    Bla Elfa    Flq
Item_A: 1   0   5   0   0
Item_B: 1   0   0   2   2
Item_C: 1   0   4   2   2
Item_D: 0   3   4   2   0

Связанный контент