Поиск различных возможных комбинаций

Файл A имеет ряды генов:

A,B,C,D,E
P,Q,R
G,D,V,K
L,Q,X,I,U,G и так далее.

Рассматривая каждый ряд по очереди, как можно получить следующий вид вывода:

Для первого ряда:

A,B,C
B,C,D
C,D,E

Для второго ряда:

P,Q,R

Для третьего ряда:

G,D,V
D,V,K

По сути, я хотел бы найти "триплеты" генов из каждого ряда. Первая тройка будет содержать первые три гена. Во втором триплете будут второй, третий, четвертый гены. Последний триплет будет заканчиваться последним геном в ряду.
Добиться этого вручную будет непростой задачей. Поскольку мне еще предстоит освоить Linux, Perl или Python, чтобы иметь возможность написать скрипт для этого, помощь сообщества будет оценена по достоинству!

-1
30.05.2017, 04:29
3 ответа

Использованиеawk:

function wprint() {
    print w[1], w[2], w[3];
}

function wshift(e) {
    w[1] = w[2]; w[2] = w[3]; w[3] = e;
}

BEGIN { FS = OFS = "," }

{
    wshift($1);
    wshift($2);
    wshift($3);
    wprint();

    for (i = 4; i <= NF; ++i) {
        wshift($i);
        wprint();
    }
}

Тогда:

$ awk -f script data.in
A,B,C
B,C,D
C,D,E
P,Q,R
G,D,V
D,V,K
L,Q,X
Q,X,I
X,I,U
I,U,G

Сценарий awkиспользует движущееся окно из трех элементов, w. Для каждой входной строки он заполняет три элемента окна тремя первыми полями и печатает их в виде списка, разделенного запятыми -(, за которым следует новая строка ). Затем он перебирает оставшиеся поля в строке, сдвигая их в окно и печатая окно для каждого элемента.

Если какая-либо строка во входных данных содержит менее двух полей, вы получите что-то вроде

A,,

или

A,B,

на выходе.

Если вы уверены, что каждая строка ввода имеет как минимум три поля (, или если вы хотите игнорировать любую строку, которая не содержит ), вы можете немного сократить скрипт awk:

function wprint() {
    print w[1], w[2], w[3];
}

function wshift(e) {
    w[1] = w[2]; w[2] = w[3]; w[3] = e;
}

BEGIN { FS = OFS = "," }

{
    for (i = 1; i <= NF; ++i) {
        wshift($i);
        if (i >= 3) {
            wprint();
        }
    }
}

Обобщение первой вариации скрипта с переменным размером окна:

function wprint(i) {
    for (i = 1; i < n; ++i) {
        printf("%s%s", w[i], OFS);
    }
    print w[n]
}

function wshift(e,i) {
    for (i = 1; i < n; ++i) {
        w[i] = w[i + 1];
    }
    w[n] = e;
}

BEGIN { FS = OFS = "," }

{
    for (i = 1; i <= n; ++i) {
        wshift($i);
    }
    wprint();

    for (i = n + 1; i <= NF; ++i) {
        wshift($i);
        wprint();
    }
}

Использование:

$ awk -v n=4 -f script data.in
A,B,C,D
B,C,D,E
P,Q,R,
G,D,V,K
L,Q,X,I
Q,X,I,U
X,I,U,G
1
28.01.2020, 05:07

Используя Perl, мы можем решить это следующим образом:

perl -lne '/(?:([^,]+)(?=((?:,[^,]+){2}))(?{ print $1,$2 }))*$/' yourfile
perl -F, -lne '$,=","; print shift @F, @F[0..1] while @F >= 3' 
perl -F, -lne '$,=","; print splice @F, 0, 3, @F[1,2] while @F >= 3'

что можно записать в расширенном виде, как показано ниже:

perl -lne '
   m/
      (?:                       # set up a do-while loop
         ([^,]+)                # first field which shall be deleted after printing
         (?=((?:,[^,]+){2}))    # lookahead and remember the next 2 fields
         (?{ print $1,$2 })     # print the first field + next 2 fields
      )*                        # loop back for more
      $                         # till we hit the end of line
   /x;
' yourfile

И с помощью sed мы можем сделать это с набором его команд:

sed -e '
   /,$/!s/$/,/     # add a dummy comma at the EOL

   s/,/\n&/3;ta    # while there still are 3 elements in the line jump to label "a"
   d               # else quit processing this line any further

   :a              # main action
   P               # print the leading portion, i.e., that which is left of the first newline in the pattern space
   s/\n//          # take away the marker

   s/,/\n/;tb      # get ready to delete the first field
   :b

   D               # delete the first field, and apply the sed code all over from the beginning to what remains in the pattern space
' yourfile

Dc также может сделать это:

sed -e 's/[^,]*/[&]/g;y/,/ /' gene_data.in |
dc -e '
[q]sq                            # macro for quitting
[SM z0<a]sa                      # macro to store stack -> register "M"
[LMd SS zlk>b c]sb               # macro to put register "M" -> register "S"
[LS zlk>c]sc                     # macro to put register "S" -> stack
[n44an dn44an rdn10anr z3!>d]sd  # macro to print 1st three stack elements
[zsk lax lbx lcx ldx c]se        # macro that initializes & calls all other macros
[?z3>q lex z0=?]s?               # while loop to read in file line by line and run macro "e" on each line
l?x                              # main()
'

Результаты

A,B,C
B,C,D
C,D,E
D,E,F
E,F,G
P,Q,R
G,D,V
D,V,K
L,Q,X
Q,X,I
X,I,U
I,U,G
1
28.01.2020, 05:07

С perl:

perl -F, -le 'BEGIN { $, = "," } while(@F >= 3) { print @F[0..2]; shift @F }' file

С awk:

awk -F, -v OFS=, 'NF>=3 { for(i=1; i<=NF-2; i++) print $i, $(i+1), $(i+2) }' file
1
28.01.2020, 05:07

Теги

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