Unslice a string

29

1

Given an input of a list of slices of a string, output the original string.

Each slice will be given as a list of length 2, containing the start position of the slice (an integer ≥0) and the slice itself. If your language does not support arrays of arbitrary types, you may also take this as a struct or similar, or simply a string consisting of the number, a space, and then the slice.

The order of the two elements of each slice is up to you. Furthermore, if you choose to use the representation of slices as a length-2 array, you may take input as either a 2-dimensional array or a single flat array. Finally, the integer representing position may be either zero-indexed or one-indexed (all the examples here are zero-indexed).

The input will always be sufficient to determine the entire string up to the highest position given. That is, there will be no "holes" or "gaps." Therefore, the output must not contain any extra trailing or leading characters (other than the typical optional trailing newline). The input will always be consistent, and no slices will conflict with each other.

Since this is , the shortest code in bytes will win.

Test cases:

In                                                Out
-----------------------------------------------------------
[[2, "CG"], [0, "PP"], [1, "PC"]]               | PPCG
[[0, "foobarbaz"]]                              | foobarbaz
[[0, "foobar"], [6, "baz"]]                     | foobarbaz
[[2, "ob"], [5, "rba"], [0, "fooba"], [8, "z"]] | foobarbaz
[[0, "fo"], [0, "fooba"], [0, "foobarbaz"]]     | foobarbaz

Doorknob

Posted 2016-02-22T17:05:24.813

Reputation: 68 138

Is there any restrictions on what characters the string will contain? – GamrCorps – 2016-02-22T18:01:58.790

@GamrCorps Nope, no special restrictions. – Doorknob – 2016-02-22T18:06:13.860

1Are there any restrictions on the length of the output string? – Mego – 2016-02-22T18:43:43.900

@Mego None aside from natural limits imposed by memory/storage. – Doorknob – 2016-02-22T19:58:53.047

1HA! This is the undo mechanism in my text editor :D – slebetman – 2016-02-23T02:45:00.213

Can there be trailing spaces in the slices? – Adám – 2016-02-29T13:00:12.853

@Nᴮᶻ Solutions should be able to support slices containing any printable ASCII characters. – Doorknob – 2016-02-29T13:25:35.503

Answers

5

Jelly, 10 9 bytes

Ḣ0ẋ;Fµ€o/

Try it online!

How it works

Ḣ0ẋ;Fµ€o/  Main link. Input: A (list of pairs)

     µ€    Convert the chain to the left into a link, and apply it to each pair.
Ḣ          Pop the first element.
 0ẋ        Yield a list of that many zeroes.
   ;F      Concatenate the list of zeroes with the popped, flattened pair.
       o/  Reduce the generated lists by logical OR.
           Since all characters are truthy, this overwrites zeroes with characters,
           but never characters with zeroes.

Dennis

Posted 2016-02-22T17:05:24.813

Reputation: 196 637

14

Python 2, 49 bytes

lambda l:`map(max,*[' '*n+s for n,s in l])`[2::5]

First, lines up the strings by padding their offsets with spaces (shown as underscores for clarity)

[[2, "CG"], [0, "PP"], [1, "PC"]] 

__CG
PP
_PC

Then, uses map to zip and take the maximum of each column, which ignores the smaller values of spaces (the smallest printable character) and Nones where some strings were too short.

__CG
PP
_PC

PPCG

Finally, ''.join to a string using the [2::5] trick.

xnor

Posted 2016-02-22T17:05:24.813

Reputation: 115 687

Whats the 2::5 trick? How does that join a string? Isn't that every 5th index starting at 2? – Robert Fraser – 2016-02-29T12:35:05.813

@RobertFraser See here.

– xnor – 2016-02-29T23:30:13.980

8

JavaScript (ES6), 61 bytes

a=>a.map(([o,s])=>[...s].map(c=>r[o++]=c),r=[])&&r.join``

Edit: Saved 4 bytes thanks to @edc65.

Neil

Posted 2016-02-22T17:05:24.813

Reputation: 95 035

a=>a.map(([o,s])=>[...s].map(c=>r[o++]=c),r=[])&&r.join`` saves 4 bytes – edc65 – 2016-02-29T08:41:13.120

8

Perl, 25

Added +2 for -lp

Get the input from STDIN, e.g.

perl -lp slices.pl
2 CG
0 PP
1 PC

(Close with ^D or ^Z or whatever closes STDIN on your system)

slices.pl:

/ /;$r|=v0 x$`.$'}{*_=r

Ton Hospel

Posted 2016-02-22T17:05:24.813

Reputation: 14 114

Wouldn't the null byte instead of v0 save you two bytes (because you could also omit the space before the x)? Edit: Hm, no, when I tried it, I got Can't locate object method "x" via package "2" (or whatever the number is on my first line) for some reason. – msh210 – 2016-02-24T22:17:19.153

1Only names like C variables can be unquoted literals. So v0 is the shortest way to get \0 (or a \0 between quotes for a tie in this case due to the extra space) – Ton Hospel – 2016-02-24T22:24:41.767

7

Haskell, 57 bytes

import Data.List
map snd.sort.nub.(>>= \(n,s)->zip[n..]s)

Usage example:

*Main> map snd.sort.nub.(>>= \(n,s)->zip[n..]s) $ [(2,"CG"),(0,"PP"),(1,"PC")]
"PPCG"

How it works: make pairs of (index,letter) for every letter of every slice, concatenate into a single list, remove duplicates, sort by index, remove indices.

nimi

Posted 2016-02-22T17:05:24.813

Reputation: 34 639

4

MATL, 15 bytes

''i"@Y:Y:tn:b+(

Works with current version (13.0.0) of the language/compiler.

Input is with curly braces and single quotes. (Curly braces in MATLAB/MATL define cell arrays, which are lists that can have contents of arbitrary, possibly different types.) The test cases are thus:

{{2, 'CG'}, {0, 'PP'} {1, 'PC'}}
{{0, 'foobarbaz'}}
{{0, 'foobar'}, {6, 'baz'}}
{{2, 'ob'}, {5, 'rba'}, {0, 'fooba'}, {8, 'z'}}
{{0, 'fo'}, {0, 'fooba'}, {0, 'foobarbaz'}}

Try it online!

''      % push empty string. This will be filled with the slices to produce the result
i       % take input: cell array of cell arrays. For example: {{0, 'foobar'}, {6, 'baz'}}
"       % for each (1st-level) cell
  @     %   push that cell. Example: {{0, 'foobar'}}
  Y:    %   unpack (1st-level) cell, i.e. push its contents. Example: {0, 'foobar'}
  Y:    %   unpack (2nd-level) cell array: gives number and substring. Example: 0, 'foobar'
  tn:   %   duplicate substring and generate vector [1,2,...,n], where n is length of
        %   current substring (in the example: 6)
  b+    %   add input number that tells the position of that substring within the whole
        %   string (in the example: 0; so this gives [1,2,...,6] again)
  (     %   assign substring to the total string, overwriting if necessary. Note that
        %   MATL uses 1-indexing
        % end for each
        % implicit display

Luis Mendo

Posted 2016-02-22T17:05:24.813

Reputation: 87 464

1This answer's a bute! – Conor O'Brien – 2016-02-22T17:44:57.507

3

DUP, 14 bytes

[0[$;$][,1+]#]

Try it here.

Anonymous lambda. Usage:

2"CG"0"PP"1"PC"[0[$;$][,1+]#]!

NOTE: DUP does not really have arrays, so I hope this input format is okay.

Explanation

Well, DUP's string comprehension is... interesting. Strings are stored as a series of number variables, each of which holds a charcode from the string. Something like 2"CG" works as pushing 2 to the stack, then creating a string with index starting from 2.

Because these indexes are really variables, they can be overwritten. That's what the input is really doing: overriding! Try pressing Step on the interpreter site to get a better idea for this. After this, we get an unsliced string.

This is where the outputting comes in.

[            ] {lambda}
 0             {push 0 to the stack as accumulator}
  [   ][   ]#  {while loop}
   $;$         {duplicate, get var at TOS value, see if that var is defined}
        ,1+    {if so, output charcode at TOS and increment accumulator}

Mama Fun Roll

Posted 2016-02-22T17:05:24.813

Reputation: 7 234

Hooray for DUP! – cat – 2016-02-25T23:22:23.007

2

PHP, 146 chars

Note: Evaling user input is always a good idea.

Golfed

<?$a=[];$f=0;eval("\$b={$argv[1]};");foreach($b as$d){$f=$d[0];$e=str_split($d[1]);foreach($e as$c){$a[$f++]=$c;}}ksort($a);echo join('',$a)."\n";

Ungolfed

<?php
$array = array();
$p = 0;
eval("\$input = {$argv[1]};");
foreach($input as $item)
{
    $p = $item[0];
    $str = str_split($item[1]);
    foreach($str as $part)
    {
        $array[$p++] = $part;
    }
}
ksort($array);
echo join('', $array)."\n";
?>

You can see that I'm just writing the input into an array with the specific key each char has and then output it all.

Tests

php unslice.php '[[0, "foobar"], [6, "baz"]]' -> foobarbaz

php unslice.php '[[2, "CG"], [0, "PP"], [1, "PC"]]' -> PPCG

php shorten.php unslice.php -> Shortened script by 107 chars. :D

timmyRS

Posted 2016-02-22T17:05:24.813

Reputation: 329

"Evaling user input is never a good idea" Code Golf is about worst-practices :D – cat – 2016-02-25T23:26:21.950

$a[$f]=$c;$f++; I don't know PHP but can't this be $a[$f++]=c; ? – cat – 2016-02-25T23:27:01.123

Ill try it.. :D – timmyRS – 2016-02-27T07:25:24.037

@cat Thx mate, shorted it by 3 chars. :D – timmyRS – 2016-02-27T09:20:39.583

1

Python, 91 bytes.

Saved 1 byte thanks to cat.

It's a bit long. I'll golf it down more in a bit.

def f(x):r={j+i:q for(i,s)in x for j,q in enumerate(s)};return"".join(map(r.get,sorted(r)))

Morgan Thrapp

Posted 2016-02-22T17:05:24.813

Reputation: 3 574

1

Seriously, 48 bytes

,`i@;l(;)+(x@#@k`M;`i@X@M`MMu' *╗`iZi`M`i╜T╗`MX╜

Seriously is seriously bad at string manipulation.

Try it online!

Explanation:

,`i@;l(;)+(x@#@k`M;`i@X@M`MMu' *╗`iZi`M`i╜T╗`MX╜
,                                                 get input
 `              `M;                               perform the first map and dupe
                   `     `MM                      perform the second map, get max element
                            u' *╗                 increment, make string of that many spaces, save in reg 0
                                 `   `M           third map
                                       `    `M    fourth map
                                              X╜  discard and push register 0

Map 1:

i@;l(;)+(x@#@k
i@;l            flatten, swap, dupe string, get length
    (;)+(       make stack [start, end, str]
         x@#@k  push range(start, end), explode string, make list of stack

Map 2:

i@X@M
i@X     flatten, swap, discard (discard the string)
   @M   swap, max (take maximum element from range)

Map 3:

iZi  flatten, zip, flatten (make list of [index, char] pairs)

Map 4:

i╜T╗  flatten, push reg 0, set element, push to reg 0

In a nutshell, this program makes a string with n spaces, where n is the minimum length the string can be based on the input. It determines the index in the result string of each character in each slice, and sets the character in the result string at that index to the character.

Mego

Posted 2016-02-22T17:05:24.813

Reputation: 32 998

1

Python, 119 115 bytes

def f(x,s=""):
 x.sort()
 for e in x:
  a=e[0];b=e[1]
  for i,c in enumerate(b):
   if len(s)<=(i+a):s+=c
 return s

Test cases

enter image description here

Argenis García

Posted 2016-02-22T17:05:24.813

Reputation: 223

0

CJam, 26 bytes

q~{~0c*\+}%{.{s\s|}}*e_0c-

Try it online!. Takes input in form [["CG"2]["PP"0]["PC"1]].

Explanation:

q~           Read and eval input

{~0c*\+}%    Convert input strings into workable format
{      }%     Map onto each input
 ~            Evaluate
  0c          Null character
    *\+       Multiply by input number and concat to string

{.{s\s|}}*   Combine strings
{       }*    Fold array
 .{    }       Vectorize, apply block to corresponding elements of arrays
   s\s         Convert elements to strings
      |        Set Union

e_0c-        Remove null characters

GamrCorps

Posted 2016-02-22T17:05:24.813

Reputation: 7 058

0

R, 181 bytes

n=nchar;m=matrix(scan(,'raw'),ncol=2,byrow=T);w=rep('',max(n(m[,2])+(i<-strtoi(m[,1]))));for(v in 1:nrow(m)) w[seq(i[v]+1,l=n(m[v,2]))]=unlist(strsplit(m[v,2],''));cat("",w,sep="")

With line breaks:

n=nchar
m=matrix(scan(,'raw'),ncol=2,byrow=T)
w=rep('',max(n(m[,2])+(i<-strtoi(m[,1]))))
for(v in 1:nrow(m)) w[seq(i[v]+1,l=n(m[v,2]))]=unlist(strsplit(m[v,2],''))
cat("",w,sep="")

Works in R Gui (single line one, or sourcing for the multi-line one) but not in ideone, example:

> n=nchar;m=matrix(scan(,'raw'),ncol=2,byrow=T);w=rep('',max(n(m[,2])+(i<-strtoi(m[,1]))));for(v in 1:nrow(m)) w[seq(i[v]+1,l=n(m[v,2]))]=unlist(strsplit(m[v,2],''));cat("",w,sep="")
1: 2 ob 5 rba 0 fooba 8 z
9: 
Read 8 items
foobarbaz

Note on the input method:

or simply a string consisting of the number, a space, and then the slice.

I assume I comply with this part of the spec with this kind of input, it can be given on multiple lines, this has no impact as long as there a blank line to end the input.

I think 2 chars can be saved by removing the +1 and using 1 based indexing but I started with challenge input.

Tensibai

Posted 2016-02-22T17:05:24.813

Reputation: 409

0

C, 110 bytes

c,i,j;char s[99];main(){while(~scanf("%i ",&i))for(;(c=getchar())>10;s[i++]=c);for(;s[j]>10;putchar(s[j++]));}

This program takes the slice after its index in one line of input each.

Ungolfed:

c,i,j;char s[99];

main(){
    while(~scanf("%i ",&i))
        for(;(c=getchar())>10;s[i++]=c);
    for(;s[j]>10;putchar(s[j++]));
}

Test on ideone.com

removed

Posted 2016-02-22T17:05:24.813

Reputation: 2 785

0

Lua, 113 bytes

z=loadstring("return "..io.read())()table.sort(z,function(a,b)return a[1]<b[1]end)for a=1,#z do print(z[a][2])end

This is probably some of the more secure code I've written. The idea is simple. The user will enter an array formatted as so: {{1, "1"}, {3, "3"}, {2, "2"}} and then the table will be sorted by the first index and the second index will be printed.

Skyl3r

Posted 2016-02-22T17:05:24.813

Reputation: 399