# Running gene crossover algorithm

Your task is to accept as input two gene sequences, and a sequence of "cross over points", and return the gene sequence that results from the indicated cross overs.

What I mean by this is, say you have the sequences [A, A, A, A, A, A, A] and [Z, Z, Z, Z, Z, Z, Z], and cross over points of 2 and 5. The resulting sequence would be [A, A, Z, Z, Z, A, A], because:

Cross Here:   V     V
Indices:  0 1 2 3 4 5 6

Genes 1:  A A A A A A A
Genes 2:  Z Z Z Z Z Z Z

Result:   A A Z Z Z A A
^     ^


Note that while I'm using letters here for clarity, the actual challenge uses numbers for genes.

The result is the first sequence until a cross over point is encountered, then the result takes from the second sequence until another cross over point is encountered, then the result takes from the first sequence until a cross over point is encountered...

# Input:

• Input can be any reasonable form. The two sequences can be a pair, with the points as the second argument, all three can be separate arguments, a single triplet of (genes 1, genes 2, cross-points), a map with named keys...

• The cross points will always be in order, and will always be inbounds. There won't be duplicate points, but the list of cross over points may be empty.

• Gene sequences will always be the same length, and will be non-empty.

• Indices can be 0 or 1 based.

• Genes will always be numbers in the range 0-255.

• It doesn't matter which argument is "genes 1" or "genes 2". In the case of no cross over points, the result can either be either entirely "genes 1" or "genes 2".

# Output

• Output can be any reasonable form that isn't ambiguous. It can be a array/list of numbers, an array of string numbers, a delimited string of numbers (some non-numeric character must separate the numbers)...

• It can be returned or printed to the std-out.

Entries can by full programs or functions.

# Test Cases (genes 1, genes 2, cross points) => result:

, ,  => 
[0, 1], [9, 8],  => [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]


This is Code Golf.

• Your worked example would be a bit clearer if the crossover indices weren't also elements in the sequences. Mar 24 '18 at 23:12
• Fixed. Changed it to A's and Z's. Hope that's clearer. Mar 24 '18 at 23:22

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


The two gene sequences are taken as a pair of lists and the cross points as a second argument.

Try it 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


# JavaScript (ES6), 47 45 bytes

Saved 2 bytes thanks to @ETHproductions

Takes input as a triplet [a, b, c] where a and b are the gene sequences and c is the list of 0-indexed cross-points.

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


Try it online!

### Commented

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[j] == i //     increment j if i is equal to the next cross point
) & 1]              //   access either x or x according to the parity of j
[i++]               //   read gene at x[i] or x[i]; increment i
)                     // end of map()

• I believe you can do something like x[(j+=x[j]==i)%2][i++] to save a couple of bytes. Mar 25 '18 at 2:51
• @ETHproductions Thanks! I foolishly tried to add a 3rd variable to keep track of the pointer in x but overlooked this optimization. Mar 25 '18 at 10:41

# APL (Dyalog 16.0), 26 bytes

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


Try it online!

Input is a, c, then b. c is 1 indexed.

How?

a←⎕ - get a.

0⍴⍨≢ - create array of 0s at its length.

1@⎕⊢ - take c and change the 0s to 1s on the indices.

d← - assign to d.

⊂≠\d - expand d with xor to create the selection sequence (0 for a, 1 for b), and enclose.

(~,⊢) - take d and its inverse.

a⎕× - and multiply respectively with inputted b and a.

+/ - sum each pair of elements, yielding the as on 0s and bs on 1s.

• ⊢0⍴⍨≢ -> ≠⍨ (tip)
– ngn
Mar 25 '18 at 3:16
• @ngn I can't get it to work [tio] Mar 25 '18 at 8:59
• you need a , before 1-element vectors in the input
– ngn
Mar 25 '18 at 14:36

# Python 2, 43 bytes

def f(a,b,l):
for p in l:a[p:],b=b[p:],a*1


Try it online!

Outputs by modifying the argument a. Instead as a program:

50 bytes

a,b,l=input()
for p in l:a[p:],b=b[p:],a*1
print a


Try it online!

# Perl 5-a, 45 40 bytes

Give input in the order "control", "second sequence", "first sequence" as separate lines on STDIN

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


Try it online!

# J, 24 bytes

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


Try it online!

I don't count the f=: chars, because it works equally well as an anonymous function (as demonstrated in a TIO sample)

Note: It doesn't work for empty list of cross over points!

An explicit oneliner, x is the left argument - the list of cross over points, y is the right argument, a two-row table of the sequences.

## Explanation:

4 :' ... ' - a dyadic verb

(...)}y - Each atom of operand (...) selects an atom from the corresponding positions of the items of y

#{.y - takes the first sequence and find its length

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


I. creates a list of zeros with length the argument

   I.6
0 0 0 0 0 0


1 x} changes the items of the rigth argument (a list of zeroes) to 1 at indices indicated by x (the list of cors over points)

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


+/\ running sums of a list

   +/\ 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


Assembled:

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


# 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}


Try it online!

Takes input as a matrix of 2 columns and a vector.

# Python 3, 61 60 bytes

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


Try it online!

-1 byte from Jonathan Frech

Explanation:

f=lambda a,b,c,d=0:c and a[d:c]+f(b,a,c[1:],c)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]
#  return the items of the first list from the
#  starting point up to the first crossover
+f(b,a,c[1:],c)
#  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

• Possible 60 bytes; assuming that a[d:c]+f(b,a,c[1:],c) will never be false. Mar 25 '18 at 13:30

# Jelly, 12 10 bytes

ṁ⁹L‘¤ḣ"ḷ"/


Try it online!

Argument 1: seq1, seq2
Argument 2: cross points (0-indexed)

• There was a reason... this does not work for one of the test cases! Mar 24 '18 at 23:56
• Also fails in other scenarios, e.g. Mar 25 '18 at 0:01
• Looks like something like ;⁹ZL‘¤Ṭ+\ịŒDḢ would be required :( Mar 25 '18 at 0:11
• @JonathanAllan I actually managed to find a 12-byte version quite different than what you suggested. :) Mar 25 '18 at 10:37
• @JonathanAllan ...and then I discovered a completely different 10-byte version, checked with both your links and another test case (relax, I did remember to change to 0-based indexing). :D Mar 25 '18 at 11:50

# Jelly, 13 bytes

ṬœṗÐ€ż/JḂị"ƊF


A dyadic link accepting the (1-indexed) crossover points on the left and a list of the two sequences on the right which returns the resulting list.

Try it online!

### How?

ṬœṗÐ€ż/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   [,[2,4],[6,8],]  /  [,[3,5],[7,9],]
/       - reduce with:
ż        -   zip                           [[,],[[2,4],[3,5]],[[6,8],[7,9]],[,]]
J      -   range of length               [1,2,3,4]
Ḃ     -   bit (modulo by 2)             [1,0,1,0]
"   -   zip with:
ị    -     index into                  [,[3,5],[6,8],]
F - flatten                         [0,3,5,6,8,1]

• @Carcigenicate - thanks I just noticed after asking :D Mar 24 '18 at 23:18
• Ḃ: What a useless thing for indexing into a 2-element list. ż/: How useless of a complication, it's cruelly flattened away by a big truck anyway! Mar 24 '18 at 23:46

# Charcoal, 19 bytes

ＡθＡηＥ§θ⁰§§θＬΦ⊕κ№ηλκ


Try it online! Link is to verbose version of code. Takes input as a pair of string gene sequences and a 0-indexed list of crossing points. Explanation:

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


Alternatively, ⭆ could be subsituted for Ｅ to print the result as a string. Try it online!

# 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.


Usage: Call "Genes1/Genes2/CrossoverPoints/X" where "Genes1", "Genes2", "CrossoverPoints" are bracket-enclosed, comma-separated lists.

# C (clang), 79 bytes

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


Try it online!

Inputs:
g is gene-sequence 1,
g is gene-sequence 2,
c is cross-over points.
l is length of g and g
m is length of c
All array inputs are arrays of integers with 0-based index.

Outputs:
Output is stored in g

macro a() in footer does pretty-printing of test-cases and result