Interleave strings

30

1

Inspiration.* I cannot believe we have not had this challenge before:

Task

Given one or more printable ASCII strings, interleave them by taking one character from each string, cyclically until out of characters. If a string runs out of characters before the others, just skip that one from then on.

Examples

SIMPLE gives SIMPLE

POLLS and EPEES gives PEOPLELESS

LYES and APRONS gives LAYPERSONS

ABCDE and a c and 123 567 gives Aa1B 2Cc3D E567

"\n$?* and (empty string) and ,(.)" (trailing space) gives ",\(n.$)?"* (trailing space)


* There are shorter APL solutions.

Adám

Posted 2016-12-08T12:07:35.710

Reputation: 37 779

Since this is basically just a transpose operation, we've had a few challenges that are very similar, but possibly none that are exactly the same. – Martin Ender – 2016-12-08T12:10:32.533

7I had this question on my CS HW, does that mean I can close this as a homework question? ;P – Downgoat – 2016-12-08T14:40:38.203

@EriktheOutgolfer Cool! I learned something today. – Adám – 2017-04-16T06:42:18.823

Answers

23

Jelly, 1 byte

Z

Try it online!

The “transpose” built-in will do exactly this to a list of strings.

Lynn

Posted 2016-12-08T12:07:35.710

Reputation: 55 648

I'm curious, what would the code have looked like if you had to pad short strings with spaces? – Adám – 2016-12-08T13:33:31.937

2

That would be z⁶. z is “transpose left, padding with right”; is a space.

– Lynn – 2016-12-08T13:47:09.573

And what if built-ins doing the exact job were not allowed? – Adám – 2016-12-08T15:38:27.797

1@Adám Jelly works very well on lists; where do built-ins end and language constructs / design begin? – steenbergh – 2016-12-08T15:44:18.773

1@Lynn In Jelly? Anything on the Atoms and Quicks lists are buildt-ins. – Adám – 2016-12-08T16:08:38.627

2@Adám ;" (element-wise concatenation) would solve the task without a built-in. – Dennis – 2016-12-08T17:04:09.297

@Dennis ;"/ tbf – Erik the Outgolfer – 2017-08-01T17:24:06.347

8

Python 2, 101 89 86 69 bytes

I'm hoping I can get this into a lambda somehow, shortening it down by making it recursive. It isn't ideal because you would hope transposing is shorter, unfortunately it isn't (from what I have managed to come up with so far).

f=lambda s:' '*any(s)and''.join(x[:1]for x in s)+f([x[1:]for x in s])

Old solutions:

w=input();o=''
while any(w):
 for i in range(len(w)):o+=w[i][:1];w[i]=w[i][1:]
print o

lambda s:''.join(''.join([c,''][c<' ']for c in x)for x in map(None,*[list(y)for y in s]))

w=input();o=''
while any(x>=' 'for x in w):
 for i in range(len(w)):o+=w[i][:1];w[i]=w[i][1:]
print o

thanks to mathmandan for making me feel dumb ;) saved me a bunch of bytes! (on an old solution)

Kade

Posted 2016-12-08T12:07:35.710

Reputation: 7 463

Couldn't you just do while any(w):? Empty strings are falsey in Python. – mathmandan – 2016-12-08T13:30:17.893

@mathmandan You're absolutely right, don't know what I was thinking.. – Kade – 2016-12-08T13:33:54.507

No problem :) Your new solution looks great, except I think you need to prepend f=. – mathmandan – 2016-12-08T13:54:52.033

You can take the [] off of the recursive call, leaving f(x[1:] for x in s), that makes it a generator comprehension, which acts the same as a list in this context. – bioweasel – 2017-08-01T17:37:34.587

8

Perl 6, 34 32 bytes

{[~] flat roundrobin |$_».comb}

{roundrobin(|$_».comb).flat.join}

A lambda that takes an array of strings as argument, and returns a string.

(Try it online)

smls

Posted 2016-12-08T12:07:35.710

Reputation: 4 352

I would have used @_ instead of $_ – Brad Gilbert b2gills – 2016-12-08T19:13:39.040

7

CJam, 4 bytes

qN/z

Try it online!

We can also write an unnamed function for 4 bytes, which expects a list of strings on top of the stack:

{zs}

Try it online!

Martin Ender

Posted 2016-12-08T12:07:35.710

Reputation: 184 808

2That's one byte a minute! – Adám – 2016-12-08T12:12:53.737

7

Pyth - 3 bytes

Very simple, will add expansion later, on mobile.

s.T

Test Suite

s                         Join all the strings together
 .T                       Transpose, without chopping off overhang
  (Q implicit)

Maltysen

Posted 2016-12-08T12:07:35.710

Reputation: 25 023

4@Daniel I'm in school too :P – Maltysen – 2016-12-08T14:31:46.040

Any plans on adding the explanation? – John Dvorak – 2017-04-14T14:14:23.837

@JanDvorak sure doing it now. – Maltysen – 2017-04-16T00:17:47.883

6

JavaScript (ES6), 52 46 bytes

f=([[c,...s],...a])=>s+a?c+f(s+s?[...a,s]:a):c

Takes input as an array of strings and outputs as a single string.

Test snippet

f=([[c,...s],...a])=>s+a?c+f(s+s?[...a,s]:a):c

g=a=>console.log("Input:",JSON.stringify(a),"Output:",JSON.stringify(f(a)))

g(["SIMPLE"])
g(["POLLS","EPEES"])
g(["LYES","APRONS"])
g(["ABCDE","a c","123 567"])
g(["\"\\n$?*",",(.)\" "]) // Backslash and quote are escaped, but in/output are correct

ETHproductions

Posted 2016-12-08T12:07:35.710

Reputation: 47 880

f=([[c,...s],...a])=>c?c+f([...a,s]):a+a&&f(a) – Neil – 2016-12-08T14:06:34.330

@Neil That's a great approach. I managed to golf 6 bytes off my own :-) – ETHproductions – 2016-12-08T15:35:30.973

6

Haskell, 33 bytes

import Data.List
concat.transpose

Try it on Ideone. Usage:

Prelude Data.List> concat.transpose$["ABCDE","a c","123 567"]
"Aa1B 2Cc3D E567"

Without using a build-in: (38 34 bytes)

f[]=[]
f x=[h|h:_<-x]++f[t|_:t<-x]

Try it on Ideone. 4 bytes off thanks to Zgarb! Usage:

Prelude> f["ABCDE","a c","123 567"]
"Aa1B 2Cc3D E567"

Laikoni

Posted 2016-12-08T12:07:35.710

Reputation: 23 676

1You can remove all parens in the alternative version. Still won't beat the import though. – Zgarb – 2016-12-08T16:46:59.833

Do you actually need the base case? – xnor – 2016-12-08T17:16:23.383

Never mind, of course the base case is needed. – xnor – 2016-12-08T17:24:36.517

@xnor You also can't move the base case to the end and replace it with f a=a to save a byte because both [] have a different type ... so close. – Laikoni – 2016-12-08T19:46:30.853

5

PHP, 68 67 bytes

for(;$f=!$k=$f;$i++)for(;y|$v=$argv[++$k];$f&=""==$c)echo$c=$v[$i];

Loops over command line arguments. Run with -r.

After the inner loop, $f is 1 when all strings are finished, 0 else (bitwise & casts ""==$c to int).
Next iteration of the outer loop: copy $f to $k (saves one byte from $k=0) and toggle $f:
When all strings are done, $f is now false and the loop gets broken.

Titus

Posted 2016-12-08T12:07:35.710

Reputation: 13 814

Doesn't work with empty input strings. Take a look at the last testcase – aross – 2016-12-09T11:01:12.690

@aross: fixed. thanks. – Titus – 2016-12-09T14:26:16.137

5

C, 114 84 bytes

-20 bytes for not calculating the length.

i,b;f(char**s){b=1;while(b){i=-1;b=0;while(s[++i]>0)if(*s[i])putchar(*s[i]++),++b;}}

Accepts array of char pointers and requires last item to be a null-pointer (see usage).

Ungolfed and usage:

i,b;f(char**s){
 b=1;
 while(b){
  i=-1;
  b=0;
  while(s[++i]>0)
   if(*s[i])
    putchar(*s[i]++),++b;
 }
}


int main(){
 char*a[]={ 
//  "POLLS","EPEES"
//  "LYES","APRONS"
 "ABCDE","a c","123 567"
 ,0};
 f(a);
 puts("");
}

Karl Napf

Posted 2016-12-08T12:07:35.710

Reputation: 4 131

Does the usage of printf/sprintf not allowed ? :D you would win quite some bytes. – Walfrat – 2016-12-08T14:18:39.823

@Walfrat Without printing directly I'd need to allocate a string, so how could this save anything. – Karl Napf – 2016-12-08T14:22:00.613

it was before your edit where you added the ++b and remove length compute, so yes can't work anymore. – Walfrat – 2016-12-08T14:26:11.473

@Walfrat Yes, but i had a malloc and return before and this was longer than just printing – Karl Napf – 2016-12-10T18:50:50.500

4

Retina, 13 bytes

Byte count assumes ISO 8859-1 encoding.

O$#`.
$.%`
¶

Try it online!

Explanation

O$#`.
$.%`

This is based on the standard transposition technique in Retina. We sort (O) all non-linefeed characters (.), by ($#) the number of characters in front of them on the same line ($.%`), i.e. their horizontal position.

The second stage then simply removes linefeeds from the input.

Martin Ender

Posted 2016-12-08T12:07:35.710

Reputation: 184 808

4

Java, 19+155=174 160

String f(java.util.Queue<String> q){String s,r="";while(!q.isEmpty()){s=q.poll();r+=s.isEmpty()?"":s.charAt(0);if(s.length()>1)q.add(s.substring(1));}return r;}

Ungolfed:

  String f(java.util.Queue<String> q) {
    String s, r = "";
    while (!q.isEmpty()) {
      s = q.poll();
      r += s.isEmpty() ? "" : s.charAt(0);
      if (s.length() > 1) {
        q.add(s.substring(1));
      }
    }
    return r;
  }

Output:

SIMPLE

PEOPLELESS

LAYPERSONS

Aa1B 2Cc3D E567

",(n.$)?"* ​

First modification: merged string declaration to save some bytes. Removed import, it was used by the main() method (not shown here) that also needed LinkedList. It is fewer bytes to referece Queue directly.

user18932

Posted 2016-12-08T12:07:35.710

Reputation:

initialize string s with string r can save few more – Syamesh K – 2016-12-09T11:10:37.437

I know it's been almost a year ago, but you can golf a few bytes: String f(java.util.Queue<String>q){String s,r="";for(;!q.isEmpty();r+=s.isEmpty()?"":s.charAt(0))if((s=q.poll()).length()>1)q.add(s.substring(1));return r;} – Kevin Cruijssen – 2017-09-06T08:55:18.150

3

Actually, 7 6 bytes

Golfing suggestions welcome! Try it online!

Edit: -1 byte thanks to Teal pelican.

a Z♂ΣΣ

Ungolfing

          Implicit input each string.
a         Invert the stack so that the strings are in the correct order.
<space>   Get the number of items on the stack, len(stack).
Z         Zip all len(stack) strings into one, transposing them.
♂Σ        sum() every transposed list of chars into strings.
Σ         sum() again to join the strings together.

Sherlock9

Posted 2016-12-08T12:07:35.710

Reputation: 11 664

Can you not remove the # to make it 6 bytes? – Teal pelican – 2016-12-08T15:44:31.107

@Tealpelican Welp, now I'm going to have to dig through all of my old Actually answers and see if I can't change Z♂#Σ to Z♂Σ in all of them. Thanks for the tip :D – Sherlock9 – 2016-12-08T15:49:15.293

First time looking into the language, it looks so much fun! Glad I could help :)) – Teal pelican – 2016-12-08T15:54:21.500

3

PHP, 77 bytes

Golfed

function($a){for($d=1;$d!=$s;$i++){$d=$s;foreach($a as$v)$s.=$v[$i];}echo$s;}

Anonymous function that takes an array of strings.

I'm sure this could be golfed more, but it's early. On each iteration, we grab the i-th letter from each given string and append it to our final string, one at a time. PHP just throws warnings if we access bits of strings that don't exist, so that's fine. We only stop when no changes have been made after looping through all the strings once.

I feel like the usage of $d can be golfed more, but it's early. :P

Xanderhall

Posted 2016-12-08T12:07:35.710

Reputation: 1 236

How exactly do you put an array of strings in a single argument? – Titus – 2016-12-08T13:50:49.107

@Titus. Y'know, I never really thought about it. I just kinda assumed you could. – Xanderhall – 2016-12-08T13:58:43.730

3

JavaScript (ES6), 46 bytes

f=([[c,...s],...a])=>c?c+f([...a,s]):a+a&&f(a)
<textarea oninput=o.textContent=f(this.value.split`\n`)></textarea><div id=o>

Neil

Posted 2016-12-08T12:07:35.710

Reputation: 95 035

3

Python 2, 58 bytes

lambda*m:''.join(map(lambda*r:''.join(filter(None,r)),*m))

Try it online!

Keerthana Prabhakaran

Posted 2016-12-08T12:07:35.710

Reputation: 759

Can't you remove the space in lambda *m? – Erik the Outgolfer – 2017-04-16T06:50:14.903

I just did that! Thank you! – Keerthana Prabhakaran – 2017-04-16T06:56:05.023

2

J, 13 bytes

({~/:)&;#\&.>

Try it online!

Based on the inspiration for this question.

Another way to do it takes 27 bytes but operates using transpose. Most of the bytes are to handle the automatically added zeroes from padding.

[:u:0<:@-.~[:,@|:(1+3&u:)&>

Explanation

({~/:)&;#\&.>  Input: list of boxed strings S
          &.>  For each boxed string x in S
        #\       Get the length of each prefix from shortest to longest
                 This forms the range [1, 2, ..., len(x)]
                 Rebox it
(    )         Operate on S and the prefix lengths
      &;         Raze both
   /:            Grade up the raze of the prefix lengths
 {~              Index into the raze of S using the grades
               Return

miles

Posted 2016-12-08T12:07:35.710

Reputation: 15 654

J's prohibiting mixed arrays really hurts you here. Try it in APL. – Adám – 2016-12-08T15:11:08.637

2

Bash + GNU utilities, 55

 eval paste `sed "s/.*/<(fold -1<<<'&')/g"`|tr -d \\n\\t

I/O via STDIN (line-separated) and STDOUT.

The sed formats each line to a bash process substitution. These are then evaled into paste to do the actual interleaving. tr then removes unnecessary newlines and tabs.

Ideone.

Digital Trauma

Posted 2016-12-08T12:07:35.710

Reputation: 64 644

2

PHP, 63 bytes

Note: uses IBM-850 encoding

for(;$s^=1;$i++)for(;n|$w=$argv[++$$i];$s&=$x<~■)echo$x=$w[$i];

Run like this:

php -r 'for(;$s^=1;$i++)for(;n|$w=$argv[++$$i];$s&=$x<~■)echo$x=$w[$i];' "\"\n\$?*" "" ",(.)\" " 2>/dev/null;echo
> ",\(n.$)?"* 

Explanation

for(                       # Iterate over string index.
  ;
  $s ^= 1;                 # Continue until $s (stop iterating) is 1.
                           # Flip $s so each iteration starts with $s
                           # being 1.
  $i++                     # Increment string index.
)
  for(
    ;
    "n" | $w=$argv[++$$i]; # Iterate over all input strings. OR with "n"
                           # to allow for empty strings.
    $s &= $x<~■            # If last character printed was greater than
                           # \x0 (all printable chars), set $s to 0,
                           # causing the loop to continue.
  )
    echo $x = $w[$i];      # Print char $i of current string.

aross

Posted 2016-12-08T12:07:35.710

Reputation: 1 583

IBM-850?! Is that a natural encoding for PHP? – Adám – 2016-12-09T11:48:03.460

@Adám what do you mean by "natural"? PHP treats bytes in the range 128-255 as text, which is therefore interpreted as a constant. If the constant is undefined, it will be interpreted as a string. It's so I can do ~■ (negated binary 254) instead of "\x1" (binary 1). – aross – 2016-12-09T13:02:55.520

1I see. It isn't that you actually need that codepage, you just need a 254 byte. – Adám – 2016-12-09T14:13:41.473

@Adám yes, the codepage just makes it a printable char which is a little less annoying. – aross – 2016-12-09T14:27:12.780

Great use of $$! – Titus – 2016-12-09T14:29:31.173

2

Python 3, 75 Bytes

I know the other Python one is shorter, but this is the first time I've used map ever in my life so I'm pretty proud of it

lambda n:''.join(i[k]for k in range(max(map(len,n)))for i in n if len(i)>k)

bioweasel

Posted 2016-12-08T12:07:35.710

Reputation: 307

1

C, 75 71 bytes

Only limitation is the output length. Currently it's 99, but can be easily stretched to 999 (+1 byte).

i;main(a,b)char**b;{a--;for(;i<99;i++)*b[i%a+1]&&putchar(*b[i%a+1]++);}

Ungolfed:

i;
main( a, b )
char **b;
{
    a--;
    for( ; i < 99; i++ )
        *b[i % a + 1] && putchar( *b[i % a + 1]++ );
}

Jacajack

Posted 2016-12-08T12:07:35.710

Reputation: 501

1

Python 2, 128 96

I was hoping not to have to use itertools

a=lambda a:"".join([i for i in reduce(lambda: b,c:b+c, map(None,*map(lambda m:list(m),a)) if i])

Ungolfed

 a=lambda a:                              #Start a lambda taking in a
    "".join(                              #Join the result together with empty string
        [i for i in reduce(               #For every item, apply the function and 'keep'
           lambda: b,c:b+c,               #Add lists from...
                map(None,*map(            #None = Identity function, over a map of...
                    lambda m:list(m), a)  #list made for mthe strings m
                   ) if i                 #truthy values only (otherwise the outer map will padd with None.
       ])

Pureferret

Posted 2016-12-08T12:07:35.710

Reputation: 960

Would appreciate feedback/advice on improving this. – Pureferret – 2016-12-09T16:51:20.573

1

Oracle SQL, 195 bytes

    select listagg(b,'') within group(order by l,o) from(select substr(a,level,1) b,level l,o from i start with length(a)>0 connect by prior a=a and level<=length(a) and prior sys_guid() is not null)

Takes its input from a table named i with columns a (containing the string) and o (order of the string):

    create table i (a varchar2(4000), a integer)

Explanation:
We're exploiting CONNECT BY to break up the strings into each of the characters making them up. PRIOR SYS_GUID() being NOT NULL ensures we don't end up stuck in a loop.
We then concatenate the single characters with LISTAGG but we shuffle them around with an ORDER BY clause, ordering them first by their position in the original string and only then by the string they came from.

Not as short as the other answers but SQL isn't really meant as a string manipulation language :)

Demonblack

Posted 2016-12-08T12:07:35.710

Reputation: 121

1

Perl 5, 28 bytes

26 bytes code + 2 for -0n.

s/^./!print$&/gem while/./

Try it online!

Dom Hastings

Posted 2016-12-08T12:07:35.710

Reputation: 16 415

1

R, 73 bytes

for(i in 1:max(nchar(s<-scan(,""))))for(j in seq(s))cat(substr(s[j],i,i))

Try it online!

Explanation: very simple (but verbose), just loop through printing ith character of the jth string. Fortunately, substr returns an empty string if given an out-of-range input.

user2390246

Posted 2016-12-08T12:07:35.710

Reputation: 1 391

0

Python, 112 bytes

i=len(x)if len(x)>len(y) else len(y) h=0 a="" while h<i: if h<len(x) a+=x[h] if h<len(y): a += y[h] h+=1 print a

jacksonecac

Posted 2016-12-08T12:07:35.710

Reputation: 2 584

6Your formatting is really messed up.. where do you even get x and y from? – Kade – 2016-12-08T13:35:37.673

0

Perl 5, 53 bytes

$i=0,map{push@{$a[$i++]},$_}/./g for<>;print@$_ for@a

Try it online!

Method

Creates a two dimensional array where the number of rows is equal to the length of the longest string and the maximum number of columns is equal to the number of strings. Then output each row of the array without spacing.

Xcali

Posted 2016-12-08T12:07:35.710

Reputation: 7 671

0

TXR Lisp, 20 bytes

(opip weave cat-str)

Run:

1> (opip weave cat-str)
#<intrinsic fun: 0 param + variadic>
2> [*1 "LYES" "APRONS"]
"LAYPERSONS"
3> [*1 "ABCDE" "a c" "" "123 567"]
"Aa1B 2Cc3D E567"
4> [*1 "\"\\n$?*" "" ",(.) "]
"\",\\(n.$)? *"

The weave function is lazy, so it returns a list, which is why we have to force the result to a string. Being lazy, it can weave infinite sequences. For instance, we can weave the even and odd natural numbers, which are themselves infinite lazy lists:

5> (take 20 (weave (range 2 : 2) (range 1 : 2)))
(2 1 4 3 6 5 8 7 10 9 12 11 14 13 16 15 18 17 20 19)

Kaz

Posted 2016-12-08T12:07:35.710

Reputation: 372

0

K (oK), 35 29 bytes

Solution:

{`c$r@&~^r:,/+(`i$x)[;!#,/x]}

Try it online!

Example:

> {`c$r@&~^r:,/+(`i$x)[;!#,/x]}("ABCDE";"a c";"123 567")
"Aa1B 2Cc3D E567"
> {`c$r@&~^r:,/+(`i$x)[;!#,/x]}("\n$?*";"";",(.)\" ")
"\n,$(?.*)\" "
> {`c$r@&~^r:,/+(`i$x)[;!#,/x]}("POLLS";"EPEES")
"PEOPLELESS"

Explanation:

Use 2nd-level indexing to pull out indices from 0 to max (length of flattened list) across all input lists. Any indexing beyond the bound of the sub-list will return a null. Flip (rotates 90), flatten, and then pull out the non-null results.

Notes:

  • I cast to integer (i$) so that we get useful nulls, as space () is considered null for a char list which means you cant tell nulls from valid spaces.
  • Also I couldnt get the TIO to work with input (worked fine in the oK repl) so the TIO link includes the "ABCDE"... example.

streetster

Posted 2016-12-08T12:07:35.710

Reputation: 3 635

0

Jq 1.5, 49 bytes

map(explode)|transpose|map(map(values)[])|implode

Explanation

                      # example input:          ["LYES","APRONS"]
  map(explode)        # make list of ordinals   [[76,89,69,83],[65,80,82,79,78,83]]
| transpose           # zip lists               [[76,65],[89,80],[69,82],[83,79],[null,78],[null,83]]
| map(map(values)[])  # rm nulls and flatten    [76,65,89,80,69,82,83,79,78,83]
| implode             # convert back to string  "LAYPERSONS"

Sample Run

$ paste input <(jq -Mrc 'map(explode)|transpose|map(map(values)[])|implode' input)
["SIMPLE"]                  SIMPLE
["POLLS","EPEES"]           PEOPLELESS
["LYES","APRONS"]           LAYPERSONS
["ABCDE", "a c", "123 567"] Aa1B 2Cc3D E567
["\"\\n$?*", "", ",(.)\" "] ",\(n.$)?"* 

$ echo -n 'map(explode)|transpose|map(map(values)[])|implode' | wc -c
  49    

Try it online

jq170727

Posted 2016-12-08T12:07:35.710

Reputation: 411