Działający algorytm podziału genów

16

Twoim zadaniem jest zaakceptowanie jako danych wejściowych dwóch sekwencji genów i sekwencji „punktów podziału” i zwrócenie sekwencji genów wynikającej ze wskazanych skrzyżowań.

Co mam na myśli to, że masz sekwencje [A, A, A, A, A, A, A]i [Z, Z, Z, Z, Z, Z, Z], i przejechać przez punkty 2i 5. Wynikowa sekwencja byłaby [A, A, Z, Z, Z, A, A], ponieważ:

Krzyż tutaj: VV
Wskaźniki: 0 1 2 3 4 5 6

Geny 1: AAAAAAA
Geny 2: ZZZZZZZ

Wynik: AAZZZAA
              ^ ^

Zwróć uwagę, że chociaż używam tutaj liter dla jasności, faktyczne wyzwanie wykorzystuje liczby dla genów.

Wynik jest pierwszą sekwencją do momentu napotkania punktu podziału, następnie wynik pobiera od drugiej sekwencji do napotkania innego punktu podziału, a następnie wynik trwa od pierwszej sekwencji do momentu znalezienia punktu podziału ...

Wejście:

  • Dane wejściowe mogą mieć dowolną rozsądną formę. Dwie sekwencje mogą być parą, z punktami jako drugim argumentem, wszystkie trzy mogą być osobnymi argumentami, pojedynczą tripletą (genes 1, genes 2, cross-points), mapą z nazwanymi kluczami ...

  • Punkty przecięcia zawsze będą w porządku i zawsze będą zaokrąglane. Nie będzie duplikatów punktów, ale lista punktów podziału może być pusta.

  • Sekwencje genów będą zawsze tej samej długości i nie będą puste.

  • Wskaźniki mogą być oparte na 0 lub 1.

  • Geny zawsze będą liczbami z zakresu 0–255.

  • Nie ma znaczenia, który argument to „geny 1” lub „geny 2”. W przypadku braku punktów podziału wynik może być albo całkowicie „genami 1”, albo „genami 2”.


Wynik

  • Wynik może być dowolną rozsądną formą, która nie jest dwuznaczna. Może to być tablica / lista liczb, tablica liczb ciągów, rozdzielany ciąg liczb (niektóre znaki nienumeryczne muszą oddzielać liczby) ...

  • Można go zwrócić lub wydrukować na standardowe wyjście.


Wpisy mogą mieć pełne programy lub funkcje.


Przypadki testowe (genes 1, genes 2, cross points) => result:

[0], [1], [0] => [1]
[0, 1], [9, 8], [1] => [0, 8]
[0, 2, 4, 6, 8, 0], [1, 3, 5, 7, 9, 1], [1, 3, 5] => [0, 3, 5, 6, 8, 1]
[1, 2, 3, 4], [5, 6, 7, 8], [] => [1, 2, 3, 4]
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [0, 2, 3, 6, 8] => [1, 1, 0, 1, 1, 1, 0, 0, 1, 1]

To jest Code Golf.

Carcigenicate
źródło
Twój działający przykład byłby nieco jaśniejszy, gdyby wskaźniki podziału nie były również elementami w sekwencji.
Shaggy
1
Naprawiony. Zmieniono na A i Z. Mam nadzieję, że to wyraźniejsze.
Carcigenicate

Odpowiedzi:

1

Galaretka , 12 10 bajtów

ṁ⁹L‘¤ḣ"ḷ"/

Wypróbuj online!

Argument 1: seq1, seq2
Argument 2: punkty przecięcia (indeksowane 0)

Erik the Outgolfer
źródło
Był powód ... to nie działa w jednym z przypadków testowych !
Jonathan Allan
Zawodzi również w innych scenariuszach, np.
Jonathan Allan
Wygląda na to, że coś takiego ;⁹ZL‘¤Ṭ+\ịŒDḢbyłoby wymagane :(
Jonathan Allan
@JonathanAllan W rzeczywistości udało mi się znaleźć 12-bajtową wersję zupełnie inną niż sugerowana. :)
Erik the Outgolfer
@JonathanAllan ... a potem odkryłem zupełnie inną 10-bajtową wersję, sprawdzoną zarówno z twoimi linkami, jak i innym przypadkiem testowym (zrelaksuj się, pamiętam, że zmieniłem się na indeksowanie oparte na 0). : D
Erik the Outgolfer
4

Haskell, 58 53 51 45 bajtów

(fst.).foldl(\(a,b)p->(take p a++drop p b,a))

Dwie sekwencje genów są traktowane jako para list, a punkty krzyżowe jako drugi argument.

Wypróbuj online!

foldl           -- fold the pair of genes into the list of
                -- cross points and on each step
    \(a,b) p -> -- let the pair of genes be (a,b) and the next cross point 'p'
      (take p a++drop p b,a)  
                -- let 'b' the new first element of the pair, but
                --   drop the first 'p' elements and 
                --   prepend the first 'p' elements of 'a'
                -- let 'a' the new second element 
fst             -- when finished, return the first gene   
nimi
źródło
4

JavaScript (ES6), 47 45 bajtów

Zaoszczędź 2 bajty dzięki @ETHproductions

Staje wejścia jako tryplet [a, b, c] , gdzie i b są sekwencje genowe i C lista 0 indeksowanych poprzecznych punktów.

x=>x[i=j=0].map(_=>x[(j+=x[2][j]==i)&1][i++])

Wypróbuj online!

Skomentował

x =>                    // given x = [ geneSeqA, geneSeqB, crossPoints ]
  x[i = j = 0]          // initialize i = gene sequence pointer and j = cross point pointer
  .map(_ =>             // for each value in the first gene sequence:
    x[(                 //   access x[]
      j += x[2][j] == i //     increment j if i is equal to the next cross point
    ) & 1]              //   access either x[0] or x[1] according to the parity of j
    [i++]               //   read gene at x[0][i] or x[1][i]; increment i
  )                     // end of map()
Arnauld
źródło
Wierzę, że możesz zrobić coś takiego, x[(j+=x[2][j]==i)%2][i++]aby zaoszczędzić kilka bajtów.
ETHproductions
@ETHproductions Dzięki! Głupio próbowałem dodać trzecią zmienną, aby śledzić wskaźnik w x [2], ale przeoczyłem tę optymalizację.
Arnauld,
3

APL (Dyalog 16.0) , 26 bajtów

+/a⎕×(~,⊢)⊂≠\d1@⎕⊢0⍴⍨≢a←⎕

Wypróbuj online!

Dane wejściowe to a , c , a następnie b . c jest 1indeksowane.

W jaki sposób?

a←⎕- dostać .

0⍴⍨≢- utwórz tablicę 0s na jej długości.

1@⎕⊢- weź c i zmień 0s na 1s na indeksach.

d←- przypisać do d .

⊂≠\d- rozwiń d za pomocą xor, aby utworzyć sekwencję wyboru ( 0dla a , 1dla b ), i dołącz.

(~,⊢)- weź d i jego odwrotność.

a⎕×- i pomnożyć odpowiednio przez wprowadzone b oraz a .

+/- zsumuj każdą parę elementów, uzyskując wartości a s na 0s i b s na 1s.

Uriel
źródło
⊢0⍴⍨≢-> ≠⍨( wskazówka )
ngn
@ngn Nie mogę zmusić go do pracy [tio ]
Uriel
potrzebujesz ,wejściowych wektorów 1-elementowych na wejściu
ngn
2

Perl 5 -a , 45 40 bajtów

Podaj dane wejściowe w kolejności „sterowanie”, „druga sekwencja”, „pierwsza sekwencja” jako osobne linie na STDIN

#!/usr/bin/perl -alp
@{$.}=@F}for(map${$.^=$%~~@1}[$%++],@2){

Wypróbuj online!

Ton Hospel
źródło
2

J , 24 bajty

4 :'(2|+/\1 x}I.#{.y)}y'

Wypróbuj online!

Nie liczę f=: znaków, ponieważ działa równie dobrze jak funkcja anonimowa (jak pokazano w próbce TIO)

Uwaga: Nie działa w przypadku pustej listy punktów podziału!

Wyraźny oneliner, xto lewy argument - lista punktów podziału,y to prawy argument, dwuwierszowa tabela sekwencji.

Wyjaśnienie:

4 :' ... ' - dynastyczny czasownik

(...)}y - Każdy atom operandu (...) wybiera atom z odpowiednich pozycji elementów y

#{.y - bierze pierwszą sekwencję i znajduje jej długość

    #{. 0 2 4 6 8 0,: 1 3 5 7 9 1
6

I. tworzy listę zer o długości argumentu

   I.6
0 0 0 0 0 0

1 x}zmienia pozycje argumentu rigth (lista zer) na 1 przy indeksach wskazanych przez x(lista cors nad punktami)

   1(1 3 5)}I.6
0 1 0 1 0 1

+/\ prowadzenie sum listy

   +/\ 0 1 0 1 0 1
0 1 1 2 2 3

2| moduł 2

   2|+/\ 0 1 0 1 0 1
0 1 1 0 0 1

Zmontowane:

    0 1 1 0 0 1 } 0 2 4 6 8 0 ,: 1 3 5 7 9 1
0 3 5 6 8 1
Galen Iwanow
źródło
2

R , 84 79 bajtów

function(G,K){o=G[,1]
m=1:nrow(G)
for(i in K)o[m>=i]=G[m>=i,match(i,K)%%2+1]
o}

Wypróbuj online!

Pobiera dane wejściowe jako macierz 2 kolumn i a vector.

Giuseppe
źródło
2

Python 3, 61 60 bajtów

f=lambda a,b,c,d=0:c and a[d:c[0]]+f(b,a,c[1:],c[0])or a[d:]

Wypróbuj online!

-1 bajt od Jonathana Frecha

Wyjaśnienie:

f=lambda a,b,c,d=0:c and a[d:c[0]]+f(b,a,c[1:],c[0])or a[d:]
f=lambda a,b,c,d=0:
 # recursive lambda: a and b are the two lists,
 # c is the crossovers, and d is where to start
                   c and
 # if there is at least one crossover left
 #  then
                         a[d:c[0]]
 #  return the items of the first list from the
 #  starting point up to the first crossover
                                  +f(b,a,c[1:],c[0])
 #  plus the result of the inverted lists with
 #  the remaining crossovers, starting where
 #  the first part left off
                                                    or
 # else
                                                       a[d:]
 #  the first list from the starting point to the end
pizzapanty184
źródło
1
Możliwe 60 bajtów ; zakładając, że a[d:c[0]]+f(b,a,c[1:],c[0])to nigdy nie będzie fałszywe.
Jonathan Frech,
1

Galaretka , 13 bajtów

ṬœṗЀż/JḂị"ƊF

Dyadyczne łącze akceptujące (1-indeksowane) punkty podziału po lewej stronie oraz listę dwóch sekwencji po prawej stronie, która zwraca wynikową listę.

Wypróbuj online!

W jaki sposób?

ṬœṗЀż/JḂị"ƊF - Link: list, C; list, S     e.g. [2,4,6]; [[0,2,4,6,8,0],[1,3,5,7,9,1]]
Ṭ             - untruth C                       [0,1,0,1,0,1]
   Ѐ         - map across S with:
 œṗ           -   partition at truthy indices   [[0],[2,4],[6,8],[0]]  /  [[1],[3,5],[7,9],[1]]
      /       - reduce with:
     ż        -   zip                           [[[0],[1]],[[2,4],[3,5]],[[6,8],[7,9]],[[0],[1]]]
           Ɗ  - last three links as a monad:
       J      -   range of length               [1,2,3,4]
        Ḃ     -   bit (modulo by 2)             [1,0,1,0]
          "   -   zip with:
         ị    -     index into                  [[0],[3,5],[6,8],[1]]
            F - flatten                         [0,3,5,6,8,1]
Jonathan Allan
źródło
@Carcigenicate - dzięki właśnie zauważyłem po zapytaniu: D
Jonathan Allan
: Co za bezużyteczna rzecz do indeksowania do listy 2-elementowej. ż/: Co za komplikacja, i tak okrutnie spłaszczona przez wielką ciężarówkę!
Erik the Outgolfer
1

Węgiel drzewny , 19 bajtów

AθAηE§θ⁰§§θLΦ⊕κ№ηλκ

Wypróbuj online!Link jest do pełnej wersji kodu. Pobiera dane wejściowe jako parę sekwencji genów struny i indeksowaną przez 0 listę punktów przecięcia. Wyjaśnienie:

Aθ                  Input the pair of gene sequences into `q`
  Aη                Input the list of crossing points into `h`
    E§θ⁰            Loop over one of the gene sequences
              κ     Current index
             ⊕      Incremented
            Φ  №ηλ  Intersect implicit range with crossing points
           L        Take the length
         §θ         Cyclically index into the pair of gene sequences
        §         κ Take the appropriate element of that sequence
                    Implicitly output on separate lines

Alternatywnie można zastąpić wydrukowaniem wyniku w postaci ciągu. Wypróbuj online!

Neil
źródło
1

SWI-Prolog, 78 bajtów

A/B/[0|C]/D:-B/A/C/D. [H|A]/[_|B]/C/[H|D]:-maplist(succ,E,C),A/B/E/D. A/_/_/A.

Sposób użycia: Wywołaj „Genes1 / Genes2 / CrossoverPoints / X”, gdzie „Genes1”, „Genes2”, „CrossoverPoints” to listy w nawiasach kwadratowych, oddzielone przecinkami.

ashtraypettingzoo
źródło
1

C (brzęk) , 79 bajtów

*g[2],*c,l,m;f(i,j,k){for(i=j=k=0;i<l;g[0][i++]=g[k][i])m&&c[j]==i?k=!k,j++:0;}

Wypróbuj online!

Dane wejściowe:
g[0]jest sekwencją genową 1, sekwencją
g[1]genową 2,
cstanowi punkty podziału krzyżowego.
ljest długością g[0]i g[1]
mjest długością c
Wszystkie dane wejściowe tablicy są tablicami liczb całkowitych o indeksie 0.

Wyjścia: Dane
wyjściowe są przechowywane wg[0]

makro a () w stopce robi ładne drukowanie przypadków testowych i wyniku

GPS
źródło