Laufender Gen-Crossover-Algorithmus


16

Ihre Aufgabe ist es, zwei Gensequenzen und eine Sequenz von "Crossover-Punkten" als Eingabe zu akzeptieren und die Gensequenz zurückzugeben, die sich aus den angegebenen Crossovers ergibt.

Damit meine ich, dass Sie die Sequenzen [A, A, A, A, A, A, A]und [Z, Z, Z, Z, Z, Z, Z]haben und Punkte von 2und kreuzen 5. Die resultierende Sequenz wäre [A, A, Z, Z, Z, A, A], weil:

Hier kreuzen: VV
Indizes: 0 1 2 3 4 5 6

Gene 1: AAAAAAA
Gene 2: ZZZZZZZ

Ergebnis: AAZZZAA
              ^^

Beachten Sie, dass ich hier aus Gründen der Klarheit Buchstaben verwende, während die eigentliche Herausforderung Zahlen für Gene verwendet.

Das Ergebnis ist die erste Sequenz, bis ein Überkreuzungspunkt angetroffen wird. Dann wird das Ergebnis von der zweiten Sequenz übernommen, bis ein weiterer Überkreuzungspunkt angetroffen wird. Dann wird das Ergebnis von der ersten Sequenz übernommen, bis ein Überkreuzungspunkt angetroffen wird.

Eingang:

  • Die Eingabe kann in jeder vernünftigen Form erfolgen. Die zwei Sequenzen können ein Paar sein, mit den Punkten als zweitem Argument, alle drei können separate Argumente sein, ein einzelnes Triplett von (genes 1, genes 2, cross-points), eine Karte mit benannten Schlüsseln ...

  • Die Kreuzungspunkte werden immer in Ordnung sein und werden immer eingehend sein. Es gibt keine doppelten Punkte, aber die Liste der Überkreuzungspunkte kann leer sein.

  • Gensequenzen sind immer gleich lang und nicht leer.

  • Indizes können 0 oder 1 sein.

  • Gene sind immer Zahlen im Bereich von 0 bis 255.

  • Es spielt keine Rolle, welches Argument "Gene 1" oder "Gene 2" ist. Wenn keine Kreuzungspunkte vorhanden sind, kann das Ergebnis entweder vollständig "Gene 1" oder "Gene 2" sein.


Ausgabe

  • Die Ausgabe kann in jeder vernünftigen Form erfolgen, die nicht mehrdeutig ist. Es kann ein Array / eine Liste von Zahlen sein, ein Array von Zeichenfolgenummern, eine durch Trennzeichen getrennte Zeichenfolge von Zahlen (einige nicht numerische Zeichen müssen die Zahlen trennen) ...

  • Es kann zurückgegeben oder auf die Standardausgabe gedruckt werden.


Einträge können durch vollständige Programme oder Funktionen erfolgen.


Testfälle (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]

Das ist Code Golf.


Ihr Beispiel wäre etwas klarer, wenn die Crossover-Indizes nicht auch Elemente in den Sequenzen wären.
Shaggy

1
Fest. Es wurde in A und Z geändert. Hoffe das ist klarer.
Carcigenicate

Antworten:


1

Gelee , 12 10 Bytes

ṁ⁹L‘¤ḣ"ḷ"/

Probieren Sie es online!

Argument 1: seq1, seq2
Argument 2: Kreuzungspunkte (0-indiziert)


Es gab einen Grund ... dies funktioniert nicht für einen der Testfälle !
Jonathan Allan


Sieht so aus, als ;⁹ZL‘¤Ṭ+\ịŒDḢwäre etwas erforderlich :(
Jonathan Allan

@ JonathanAllan Ich habe es tatsächlich geschafft, eine 12-Byte-Version zu finden, die ganz anders ist als von Ihnen vorgeschlagen. :)
Erik der Outgolfer

@JonathanAllan ... und dann entdeckte ich eine völlig andere 10-Byte-Version, die sowohl mit Ihren Links als auch mit einem anderen Testfall überprüft wurde (entspannen Sie sich, ich habe daran gedacht, auf 0-basierte Indizierung umzusteigen). : D
Erik der Outgolfer

4

Haskell, 58 53 51 45 Bytes

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

Die beiden Gensequenzen werden als Listenpaar und die Kreuzungspunkte als zweites Argument verwendet.

Probieren Sie es 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   

4

JavaScript (ES6), 47-45 Byte

2 Bytes gespart dank @ETHproductions

Wird als Triplett [a, b, c] eingegeben , wobei a und b die Gensequenzen und c die Liste der 0-indizierten Kreuzungspunkte sind.

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

Probieren Sie es online!

Kommentiert

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()

Ich glaube, Sie können so etwas wie x[(j+=x[2][j]==i)%2][i++]ein paar Bytes sparen.
ETHproductions

@ETHproductions Danke! Ich habe dummerweise versucht, eine dritte Variable hinzuzufügen, um den Zeiger in x [2] zu verfolgen, aber diese Optimierung übersehen.
Arnauld

3

APL (Dyalog 16.0) , 26 Bytes

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

Probieren Sie es online!

Eingabe ist a , c , dann b . c ist 1indiziert.

Wie?

a←⎕- Holen Sie sich ein .

0⍴⍨≢- Array von 0s in seiner Länge erstellen .

1@⎕⊢- nimm c und ändere das 0s in 1s auf den Indizes.

d←- Zuordnen zu d .

⊂≠\d- Erweitern Sie d mit xoder , um die Auswahlsequenz ( 0für a , 1für b ) zu erstellen , und schließen Sie sie ein.

(~,⊢)- nimm d und seine Umkehrung.

a⎕×- und multiplizieren jeweils mit eingegebenen b und a .

+/- Summiere jedes Elementpaar und ergebe die a s auf 0s und b s auf 1s.


⊢0⍴⍨≢-> ≠⍨( tip )
ngn

@ngn Ich kann es nicht zum Laufen bringen [tio ]
Uriel

Sie benötigen einen ,Vorher-1-Element-Vektor in der Eingabe
ngn


2

Perl 5 -a , 45 40 Bytes

Geben Sie die Eingabe in der Reihenfolge "Steuerung", "zweite Sequenz", "erste Sequenz" als separate Zeilen in STDIN ein

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

Probieren Sie es online!


2

J , 24 Bytes

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

Probieren Sie es online!

Ich zähle die f=:Zeichen nicht, weil es genauso gut funktioniert wie eine anonyme Funktion (wie in einem TIO-Beispiel gezeigt).

Hinweis: Es funktioniert nicht bei einer leeren Liste von Überkreuzungspunkten!

Ein expliziter Einzeiler xist das linke Argument - die Liste der Kreuzungspunkte, ydas rechte Argument, eine zweizeilige Tabelle der Folgen.

Erläuterung:

4 :' ... ' - ein dyadisches Verb

(...)}y - Jedes Atom eines Operanden (...) wählt ein Atom aus den entsprechenden Positionen der Elemente von y aus

#{.y - Nimmt die erste Sequenz und findet ihre Länge

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

I. Erstellt eine Liste von Nullen mit der Länge des Arguments

   I.6
0 0 0 0 0 0

1 x}Ändert die Elemente des rechten Arguments (eine Liste von Nullen) an den durch x(die Liste der Kors über Punkten) angegebenen Indizes in 1.

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

+/\ laufende Summen einer Liste

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

2| Modulo 2

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

Gebaut:

    0 1 1 0 0 1 } 0 2 4 6 8 0 ,: 1 3 5 7 9 1
0 3 5 6 8 1

2

R , 84 79 Bytes

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}

Probieren Sie es online!

Übernimmt die Eingabe als Matrix aus 2 Spalten und a vector.


2

Python 3, 61 60 Bytes

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

Probieren Sie es online!

-1 Byte von Jonathan Frech

Erläuterung:

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

1
Mögliche 60 Bytes ; vorausgesetzt, das a[d:c[0]]+f(b,a,c[1:],c[0])wird niemals falsch sein.
Jonathan Frech

1

Jelly , 13 Bytes

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

Ein dyadischer Link, der die (1-indizierten) Überkreuzungspunkte auf der linken Seite und eine Liste der beiden Sequenzen auf der rechten Seite akzeptiert, die die resultierende Liste zurückgibt.

Probieren Sie es online!

Wie?

ṬœṗЀż/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]

@ Carcigenicate - danke Ich habe gerade bemerkt, nachdem ich gefragt habe: D
Jonathan Allan

: Was für eine nutzlose Sache für die Indizierung in eine Liste mit 2 Elementen. ż/: Wie nutzlos von einer Komplikation, es wird sowieso grausam von einem großen Lastwagen abgeflacht!
Erik der Outgolfer

1

Holzkohle , 19 Bytes

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

Probieren Sie es online! Link ist eine ausführliche Version des Codes. Nimmt Eingaben als ein Paar von String-Gensequenzen und eine 0-indizierte Liste von Kreuzungspunkten auf. Erläuterung:

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

Alternativ könnte auch ersetzt werden , um das Ergebnis als String auszudrucken. Probieren Sie es online!


1

SWI-Prolog, 78 Bytes

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.

Verwendung: Rufen Sie "Genes1 / Genes2 / CrossoverPoints / X" auf, wobei "Genes1", "Genes2" und "CrossoverPoints" in eckigen Klammern stehende, durch Kommas getrennte Listen sind.


1

C (clang) , 79 Bytes

*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;}

Probieren Sie es online!

Eingänge:
g[0]ist Gensequenz 1,
g[1]ist Gensequenz 2,
cist Kreuzungspunkte.
list Länge von g[0]und g[1]
mist Länge von c
Alle Array-Eingaben sind Arrays von Ganzzahlen mit 0-basiertem Index.

Ausgänge: Die
Ausgabe wird in gespeichertg[0]

Das Makro a () in der Fußzeile druckt Testfälle und Ergebnisse hübsch aus

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.