Daniel Krizian
Daniel Krizian

Reputation: 4716

merge lists alternating k items from each

given list of lists, how to merge them into a single list taking up to k items at a time from each of the lists until all items are merged?

for example, the following input and output is expected:

q)alternate[1] ("abc";"de";"fghi")
"adfbegchi"

for k~1 items at a time, the solution is:

q)mesh:{raze[y]rank x}          / https://code.kx.com/phrases/sort/#mesh
q)alternate:{mesh[raze where each 1&{0|x-1}\[count each x];x]}
q)alternate ("abc";"de";"fghi")
"adfbegchi"

the above works because:

q)mesh[0 1 2 0 1 2 0 2 2;] ("abc";"de";"fghi")
"adfbegchi"

How to elegantly generalize alternate for any k<=max count each x ? python solution is here

Upvotes: 1

Views: 239

Answers (3)

Daniel Krizian
Daniel Krizian

Reputation: 4716

not sure if this is the fastest solution, substituting x for the hardcoded 1 in the alternate function above, and thus making it dyadic:

q)alternate:{mesh[raze where each x&{0|y-x}[x]\[count each y];y]}
q)alternate[2] ("abc";"de";"fghi")
"abdefgchi"
q)alternate[2] (1 2 3 4;5 6 7;8 9 10 11;12 13 14 15)
1 2 5 6 8 9 12 13 3 4 7 10 11 14 15
q)alternate[3] (1 2 3 4;5 6 7;8 9 10 11;12 13 14 15)
1 2 3 5 6 7 8 9 10 12 13 14 4 11 15

edit: naïve benchmark comparison with @terrylynch 's alt and @Matthew Madill's f :

q)\t:10000 f[2] ("abc";"de";"fghi")
49
q)\t:10000 alternate[2] ("abc";"de";"fghi")
56
q)\t:10000 alt[2] ("abc";"de";"fghi")
87
q)\t:10000 f[3] (1 2 3 4;5 6 7;8 9 10 11;12 13 14 15)
55
q)\t:10000 alternate[3] (1 2 3 4;5 6 7;8 9 10 11;12 13 14 15)
61
q)\t:10000 alt[3] (1 2 3 4;5 6 7;8 9 10 11;12 13 14 15)
103

Upvotes: 1

Matthew Madill
Matthew Madill

Reputation: 880

the below should achieve this

q)f:{raze[y]iasc raze(x-1)|til'[count'[y]]};
q)f[1;("abc";"de";"fghi")]
"adfbegchi"
q)f[2;("abc";"de";"fghi")]
"abdefgchi"

Upvotes: 4

terrylynch
terrylynch

Reputation: 13657

Not sure if this is any faster or cleaner but a different approach:

q)alt:{(raze/)value each(s;::;)each til max count each s:x cut'y};

q)alt[1;("abc";"de";"fghi")]
"adfbegchi"
q)alt[2;("abc";"de";"fghi")]
"abdefgchi"

q)alt[2;(1 2 3 4;5 6 7;8 9 10 11;12 13 14 15)]
1 2 5 6 8 9 12 13 3 4 7 10 11 14 15
q)alt[3;(1 2 3 4;5 6 7;8 9 10 11;12 13 14 15)]
1 2 3 5 6 7 8 9 10 12 13 14 4 11 15

I was hoping to use case but unfortunately case doesn't like lists of different count (that aren't atomic values)

Upvotes: 1

Related Questions