40
\$\begingroup\$

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.

\$\endgroup\$
2
  • \$\begingroup\$ 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. \$\endgroup\$ Commented Dec 8, 2016 at 12:10
  • 7
    \$\begingroup\$ I had this question on my CS HW, does that mean I can close this as a homework question? ;P \$\endgroup\$
    – Downgoat
    Commented Dec 8, 2016 at 14:40

45 Answers 45

1
2
2
\$\begingroup\$

Ruby, 86 83 71 bytes

f=->s{s[0]&&(s.reject! &:empty?;[s.map{_1[0]},f[s.map{_1[1..]}]].join)}

Attempt This Online!

A rather naive approach and my first ruby golf; later I could improve using some tips from my other Ruby golf.

  • s.reject! &:empty? removes all empty strings from the array;

  • s.map{_1[1..]} the first letters are removed;

  • s.map{_1[0]} and added to the output vector;

  • while s.length>0 s[0]&&(...) the process is repeated recursively until all strings were removed and the output vector is joined to a string.

\$\endgroup\$
2
\$\begingroup\$

Julia, 96, 79 bytes

  • Thanks to MarcMush for golfing a whopping 17 bytes! (Note that the previous version is still available as a link to the ATO site)
-,~=length,join
!a=-a<2 ? ~a : ~[(m=map(*,a...););!SubString.(a,-m+1)[.-a.>-m]]

Try it online!

I have noticed that the concatenation with map(*,a...) was a good starting point: it kind of interleaves all strings of a list with certain exceptions: the list a cannot have 1 or 0 elements and the number of the interleaved characters are limited by the size of the shortest string.

Here, the interleaved piece is recursively joined with the next part of the output where already participated characters as well as the empty string get removed.

The party ends as soon as the list a has reached the length less than 2.

Not a translation, but similar to my Ruby answer.

\$\endgroup\$
3
  • 1
    \$\begingroup\$ 79 bytes multiple improvements but it is still basically your answer \$\endgroup\$
    – MarcMush
    Commented Jul 6 at 14:05
  • \$\begingroup\$ @MarcMush thanks! that's a nice trick to replace filter / isempty with conditional subsetting, i'd never thought it works that way... \$\endgroup\$ Commented Jul 6 at 15:37
  • 1
    \$\begingroup\$ also instead of !isempty, >([]) or >("") is shorter \$\endgroup\$
    – MarcMush
    Commented Jul 6 at 15:43
1
\$\begingroup\$

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]++ );
}
\$\endgroup\$
1
\$\begingroup\$

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

\$\endgroup\$
1
\$\begingroup\$

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

\$\endgroup\$
1
\$\begingroup\$

Vyxal s, 1 byte

Try it Online!

\$\endgroup\$
1
\$\begingroup\$

Knight, 103 bytes

;=m=iF;W=xP;=mI>mLx mLxE++"=x"=i+1i" x"W+=m-mT1;=j~1W>i=j+1j;O+G E+"x"+1jF1'\'E++++"=x"+1j"Sx"+1j"F1''"

Try it online!

\$\endgroup\$
1
\$\begingroup\$

sed 4.2.2 -rz, 208 187 167 bytes

s/^|\n/\n"/g                               # prefix strings with "
:o                                         # reset loop:
s/\n\."/\n"/                               #     remove marker
s/\n"/\n."/                                #     mark first string
:h                                         # main loop:
s/([^\n]*)(.*\n\.")([^\n])(.*)/\1\3\2\4/   #     move char from marked string to output
t;:                                        #     try:
s/(.*)\n\."([^\n]*)\n"(.*)/\1\n"\2\n."\3/  #         move marker down 1 string
/^[^\n]*(\n\.?")*$/!{To;Th}                #     if (chars still present): {catch: {jump to reset loop}; jump to main loop}
s/\n.*//                                   # clean up output

Try it online!

takes input as newline-separated strings (ie you can't have newlines in your strings). this version fixes bugs related to having strings which match my string-separator markers too closely, and vastly improves the control flow.

I know that's not how try-catch statements work, but that's how sed's logic flow works. let me know if there's a better way to pseudocode it.

\$\endgroup\$
0
\$\begingroup\$

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.

\$\endgroup\$
0
0
\$\begingroup\$

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)
\$\endgroup\$
0
\$\begingroup\$

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.
\$\endgroup\$
0
\$\begingroup\$

Python3 -66

Python3 version of this one:

lambda*m:''.join(map(lambda*r:''.join([_f for _f in r if _f]),*m))

A super golfed version:

exec(bytes('慬扭慤洪✺⸧潪湩洨灡氨浡摢⩡㩲✧樮楯⡮彛⁦潦⁲晟椠⁲晩张嵦Ⱙ洪⤩','u16')[2:])
\$\endgroup\$
3
  • \$\begingroup\$ How long is the "super golfed" version? It looks longer. \$\endgroup\$
    – Wheat Wizard
    Commented Jan 29, 2022 at 19:44
  • \$\begingroup\$ It has 8 fewer characters. \$\endgroup\$
    – Gabe
    Commented Jan 30, 2022 at 14:27
  • \$\begingroup\$ Why not use a filter instead of a list comprehension like the answer you're porting from? \$\endgroup\$ Commented Aug 23, 2022 at 22:18
0
\$\begingroup\$

C# (Visual C# Interactive Compiler), 86 bytes

a=>a.SelectMany(b=>b.Select((c,i)=>(i,c))).OrderBy(b=>b.i).Aggregate("",(s,x)=>s+x.c);

Try it online!

\$\endgroup\$
0
\$\begingroup\$

Python, 68 bytes

lambda S:filter(None,chain(*zip_longest(*S)))
from itertools import*

Attempt This Online!

\$\endgroup\$
0
\$\begingroup\$

Arturo, 61 bytes

$->a[r:""a|map=>size|max|loop'i->loop a's->try->'r++s\[i-1]r]

Try it!

\$\endgroup\$
1
2

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.