Make a (somewhat) self-referential string

27

1

You want to make a string where the (1-indexed) character at index n is n. When n is less than 10, this is easy: "123456789". When n is 12, for example, it becomes impossible, since numbers greater than 9 (in base 10) take up more than one character. We can compromise by dividing the string into two-character substrings: "020406081012". Now the index of the end of each substring n is n.

This can be generalized for any d-digit number. Here's an explanation for the "0991021" part of the string for a three-digit number:

Index:     ... * 97  98  99*100 101 102*103 ...
               *           *           *
               *---+---+---*---+---+---*---+
Character: ... * 0 | 9 | 9 * 1 | 0 | 2 * 1 | ...
               *---+---+---*---+---+---*---+

If you haven't figured it out yet, you are to write a program/function that takes a string or integer and output its self-referential string as specified above. You can also output an array of single-digit numbers, chars, or single-character strings.

The given integer will always be positive and divisible by its length (e.g. 126 is divisible by 3; 4928 is divisible by 4). Your program should theoretically work for an arbitrarily large input, but you can assume it is smaller than your language's maximum integer and/or string length.

Some observations if you still don't get it: The length of the output will always be the input itself, and the numbers that appear in the output will be divisible by the number of digits in the input.

This is , so shortest answer in bytes wins.

Test cases

1    => 1
9    => 123456789
10   => 0204060810
105  => 003006009012015018021024027030033036039042045048051054057060063066069072075078081084087090093096099102105
1004 => 00040008001200160020002400280032003600400044004800520056006000640068007200760080008400880092009601000104010801120116012001240128013201360140014401480152015601600164016801720176018001840188019201960200020402080212021602200224022802320236024002440248025202560260026402680272027602800284028802920296030003040308031203160320032403280332033603400344034803520356036003640368037203760380038403880392039604000404040804120416042004240428043204360440044404480452045604600464046804720476048004840488049204960500050405080512051605200524052805320536054005440548055205560560056405680572057605800584058805920596060006040608061206160620062406280632063606400644064806520656066006640668067206760680068406880692069607000704070807120716072007240728073207360740074407480752075607600764076807720776078007840788079207960800080408080812081608200824082808320836084008440848085208560860086408680872087608800884088808920896090009040908091209160920092409280932093609400944094809520956096009640968097209760980098409880992099610001004

NinjaBearMonkey

Posted 2016-08-11T23:00:46.467

Reputation: 9 925

Answers

8

Jelly, 12 bytes

VRUmLDUz0ZFU

I/O is in form of digit arrays. Try it online! or verify all test cases.

How it works

VRUmLDUz0ZFU  Main link. Argument: A (digit array)

V             Eval; turn the digits in A into an integer n.
 R            Range; yield [1, ..., n].
  U           Upend; reverse to yield [n, ..., 1].
    L         Yield the length (l) of A.
   m          Modular; keep every l-th integer in A.
     D        Decimal; convert each kept integer into the array of its digits.
      U       Upend; reverse the digits of each integer.
       z0     Zip/transpose with fill value 0.
         Z    Zip again.
              This right-pads all digit arrays with zeroes.
          F   Flatten the resulting 2D array.
           U  Upend/reverse it.

Dennis

Posted 2016-08-11T23:00:46.467

Reputation: 196 637

7Look 'ma, no Unicode! – Dennis – 2016-08-12T01:59:01.080

8Yet it looks like some angry driver. – Jonathan Allan – 2016-08-12T02:11:17.613

12

C, 64 bytes

l,i;main(n){for(scanf("%d%n",&n,&l);i<n;)printf("%0*d",l,i+=l);}

Takes a single integer as input on stdin.

orlp

Posted 2016-08-11T23:00:46.467

Reputation: 37 067

9

JavaScript (ES6), 83 bytes

n=>[...Array(n/(l=`${n}`.length))].map((_,i)=>`${+`1e${l}`+l*++i}`.slice(1)).join``

Yes, that's a nested template string. 79 bytes in ES7:

n=>[...Array(n/(l=`${n}`.length))].map((_,i)=>`${10**l+l*++i}`.slice(1)).join``

Neil

Posted 2016-08-11T23:00:46.467

Reputation: 95 035

7

MATL, 15 14 bytes

VntG3$:10YA!1e

Try it online!

V        % Implicitly input number, n. Convert to string
n        % Length of that string, s
t        % Duplicate s
G        % Push n again
3$:      % 3-input range (s,s,n): generates [s, 2*s, ... ] up to <=n
10YA     % Convert each number to base 10. This gives a 2D array of char, with each
         % number on a row, left-padded with zeros if needed
!1e      % Reshape into a string, reading in row-major order. Implicitly display

Luis Mendo

Posted 2016-08-11T23:00:46.467

Reputation: 87 464

6

05AB1E, 15 bytes

Code:

LD¹gÖÏvy0¹g×0ñ?

Explanation:

L                # Get the array [1, ..., input].
 D               # Duplicate this array.
  ¹g             # Get the length of the first input.
    Ö            # Check if it's divisible by input length.
     Ï           # Keep those elements.
      vy         # For each...
         ¹g      # Get the length of the first input.
        0  ×     # String multiply that with "0".
            0ñ   # Merge with the number.
              ?  # Pop and print without a newline.

The merging is done like this:

From these:

000
 12

It results into this:

012

Uses the CP-1252 encoding. Try it online!.

Adnan

Posted 2016-08-11T23:00:46.467

Reputation: 41 965

Cool! Didn't know that ñ worked like that. – Emigna – 2016-08-11T23:30:25.987

1@Emigna Yeah, but it looks rather a bit long. I should probably make a builtin for that builtin :P. – Adnan – 2016-08-11T23:32:04.577

A builtin for padding would be really useful as well. – Emigna – 2016-08-11T23:33:41.927

6

Python 2, 78 70 68 64 63 bytes

Actually basing on the idea of Destructible Watermelon makes it even smaller (using input is even better)(filling the string backward saves 4 bytes)(no () at while):

n,s=input(),''
l=len(`n`)
while n:s=`n`.zfill(l)+s;n-=l
print s

Here is the old 70 byte approach (Saving 8 bytes by using backquotes instead of str and dropping the square brackets around generator thanks to Dennis):

def f(n):l=len(`n`);print"".join(`x`.zfill(l)for x in range(l,n+l,l))

Karl Napf

Posted 2016-08-11T23:00:46.467

Reputation: 4 131

I forgot about zfill... darn. – Destructible Lemon – 2016-08-12T00:00:02.393

You can use ​`x`​ instead of str(x). Also, you don't need the [] around the generator. – Dennis – 2016-08-12T00:01:52.697

You outgolfed me again... serous times call for serious measures: I'm gonna have to change to python 2 – Destructible Lemon – 2016-08-12T00:13:01.440

goddamnit you did it again! – Destructible Lemon – 2016-08-12T00:32:23.330

1You don't need the parens in while(n). – Dennis – 2016-08-12T02:18:34.790

5

Python 2, 63 bytes

def f(n):l=len(`n`);print'%%0%dd'%l*(n/l)%tuple(range(l,n+1,l))

Test it on Ideone.

Dennis

Posted 2016-08-11T23:00:46.467

Reputation: 196 637

3Dat format string °_° – Karl Napf – 2016-08-12T01:32:35.270

4

JavaScript (ES6), 66

Recursive, input n as a string (not a number) and limiting the output string size to 2GB (that is above the string limit of most javascript engines)

f=(n,i=1e9,s='',l=n.length)=>s[n-1]?s:f(n,i+=l,s+(i+'').slice(-l))

Test

f=(n,i=1e9,s='',l=n.length)=>s[n-1]?s:f(n,i+=l,s+(i+'').slice(-l))

function test() {
  var v=I.value;
  Alert.textContent=v % v.length ?
    'Warning: input value is not divisible by its string length':'\n';
  Result.textContent=f(v);
}  

test()
<input type=number id=I value=105 oninput='test()' max=500000>
<pre id=Alert></pre>
<pre id=Result></pre>

edc65

Posted 2016-08-11T23:00:46.467

Reputation: 31 086

4

R, 66 64 62 bytes

edit:

x=nchar(n<-scan());paste0(str_pad(1:(n/x)*x,x,,0),collapse="")

first golf attempt...

hedgedandlevered

Posted 2016-08-11T23:00:46.467

Reputation: 141

2Hi, and welcome to PPCG! Nice first post! – Rɪᴋᴇʀ – 2016-08-12T17:55:54.463

3

2sable, 13 bytes

Code:

g©÷F®N>*0®×0ñ

Uses the CP-1252 encoding.

Adnan

Posted 2016-08-11T23:00:46.467

Reputation: 41 965

why didn't you name this 05AB1F? :3 – Conor O'Brien – 2016-08-11T23:28:42.987

1@ConorO'Brien I actually thought about that, but then the names would look really similar and confusing :p. – Adnan – 2016-08-11T23:31:12.620

you mean 15AB1E – ASCII-only – 2016-08-12T01:23:47.570

3

Bash, 31 22 bytes

seq -ws '' ${#1}{,} $1

Test it on Ideone.

Thanks to @izabera for golfing off 6 bytes!

Dennis

Posted 2016-08-11T23:00:46.467

Reputation: 196 637

3

Brachylog, 53 45 42 37 28 bytes

lB,?ybeN:B%0,N:ef:{,"0":"9"y:?m.}acAl:Br-:"0"rjb:Acw\
lB,?ybeN:B%0,10:B^:N+:ef:{,"0":"9"y:?m.}acbw\
lB,?ybeN:B%0,10:B^:N+:ef:{:16+:@Prm.}acbw\
lB,?ybeN:B%0,10:B^:N+:efbe:16+:@Prmw\
lB,?ybeN:B%0,10:B^:N+:efbew\

Try it online!

Leaky Nun

Posted 2016-08-11T23:00:46.467

Reputation: 45 011

3

Ruby, 52 48 + n flag = 49 bytes

((l= ~/$/)..$_.to_i).step(l){|j|$><<"%0#{l}d"%j}

Value Ink

Posted 2016-08-11T23:00:46.467

Reputation: 10 608

Maybe you don’t need to chop if you assume input is passed without a trailing newline? I’m not sure if that’d work. Or how about assuming there always is one, and writing l=~-size? – Lynn – 2016-08-12T11:28:20.140

@Lynn calling size like that doesn't work for me. Oh well, I remembered a trick I had used in an earlier answer that's shorter anyways – Value Ink – 2016-08-12T18:37:24.583

2

Python 3 2, 79 74 69 65 68 67 bytes

Thanks Dennis!

def f(n):i=l=len(`n`);s='';exec n/l*"s+=`i`.zfill(l);i+=l;";print s

byte count increase from bad output method

Destructible Lemon

Posted 2016-08-11T23:00:46.467

Reputation: 5 908

1Shouldnt it be len(x) instead of f and then save bytes by assigning it to a variable? – Karl Napf – 2016-08-12T00:09:46.117

I don't think so.. what do you mean. Also, I would have outgolfed you with python 2, but some stupid stuff it happening right now ._. – Destructible Lemon – 2016-08-12T00:27:52.673

You seem to have switched to Python 2. Also, per consensus on meta, using backspace to overwrite part of the output is only allowed in ASCII art challenges.

– Dennis – 2016-08-12T00:44:21.377

In Python 2, / performs integers division foe.integer arguments. – Dennis – 2016-08-12T02:18:05.963

2

Javascript - 76

n=>eval('c="";for(a=b=(""+n).length;a<=n;a+=b)c+=`${+`1e${b}`+a}`.slice(1)')

or 71 if allowing for string arguments:

n=>eval('c="";for(a=b=n.length;a<=n;a+=b)c+=`${+`1e${b}`+a}`.slice(1)')

Thanks to @user81655!

Ungolfed:

function x(n)
{ 
   c = "", a = b = (""+n).length; 
   while(a<=n)
   {
       c=c+"0".repeat(b-(""+a).length)+a
       a+=b;
   }
   return c;
}

much place for improvement, but i'm tired right now

eithed

Posted 2016-08-11T23:00:46.467

Reputation: 1 229

Nice! I found a few improvements that could be made (76 bytes): n=>eval('c="";for(a=b=(""+n).length;a<=n;a+=b)c+=\${+`1e${b}`+a}`.slice(1)'). The main bits are using aforloop and Neil's1e${b}` trick. – user81655 – 2016-08-12T05:33:04.587

@user81655 - it gives me Uncaught SyntaxError: Invalid or unexpected token. Haven't debugged yet as I'm just awake :D – eithed – 2016-08-12T07:16:36.250

Hmmm. It might be hidden characters which are sometimes added to SO comments. Try writing it out. – user81655 – 2016-08-12T07:21:02.673

2

zsh, 28 bytes

printf %0$#1d {$#1..$1..$#1}

zsh + seq, 2120 bytes

This is pretty much the same answer as Dennis but in 20 bytes because zsh

seq -ws '' $#1{,} $1

izabera

Posted 2016-08-11T23:00:46.467

Reputation: 879

2

R, 149 142 138 bytes

x=rep(0,n);a=strtoi;b=nchar;for(i in 1:(n=scan()))if(!i%%b(a(n)))x[i:(i-b(a(i))+1)]=strsplit(paste(a(i)),"")[[1]][b(a(i)):1];cat(x,sep="")

Leaving nchar in the code gives a program with the same number of bytes than replacing it with b, but having random letters wandering around in the code makes it more... mysterious

Ungolfed :
Each nchar(strtoi(something)) permits to compute the number of numerals in a given number.

n=scan()   #Takes the integer 
x=rep(0,n) #Creates a vector of the length of this integer, full of zeros

for(i in 1:n)
    if(!i%%b(strtoi(n)))         #Divisibility check
        x[i:(i-nchar(as.integer(i))+1)]=strsplit(paste(a(i)),"")[[1]][nchar(as.integer(i)):1]; 
        #This part replace the zeros from a given position (the index that is divisible) by the numerals of this position, backward.

cat(x,sep="")

The strsplit function outputs a list of vectors containing the splitten elements. That's why you have to reach the 1st element of the list, and then the ith element of the vector, writing strsplit[[1]][i]

Frédéric

Posted 2016-08-11T23:00:46.467

Reputation: 2 059

try using str_pad() – hedgedandlevered – 2016-08-12T19:59:25.430

@hedgedandlevered : well, this function needs a package (i.e. it cannot be run with vanilla R), and I don't want to use such while PPCG-ing – Frédéric – 2016-08-22T20:40:41.493

2

Haskell, 51 bytes

f n|k<-length$show n=[k,2*k..n]>>=tail.show.(+10^k)

Lynn

Posted 2016-08-11T23:00:46.467

Reputation: 55 648

2

Perl, 40 bytes

39 bytes code + 1 for -n.

$}=y///c;printf"%0$}d",$i+=$}while$i<$_

Usage

echo -n 9 | perl -ne '$}=y///c;printf"%0$}d",$i+=$}while$i<$_'
123456789
echo -n 10 | perl -ne '$}=y///c;printf"%0$}d",$i+=$}while$i<$_'
0204060810
echo -n 102 | perl -ne '$}=y///c;printf"%0$}d",$i+=$}while$i<$_'
003006009012015018021024027030033036039042045048051054057060063066069072075078081084087090093096099102
echo -n 1000 | perl -ne '$}=y///c;printf"%0$}d",$i+=$}while$i<$_'
0004000800120016002000240028003200360040004400480052005600600064006800720076008000840088009200960100010401080112011601200124012801320136014001440148015201560160016401680172017601800184018801920196020002040208021202160220022402280232023602400244024802520256026002640268027202760280028402880292029603000304030803120316032003240328033203360340034403480352035603600364036803720376038003840388039203960400040404080412041604200424042804320436044004440448045204560460046404680472047604800484048804920496050005040508051205160520052405280532053605400544054805520556056005640568057205760580058405880592059606000604060806120616062006240628063206360640064406480652065606600664066806720676068006840688069206960700070407080712071607200724072807320736074007440748075207560760076407680772077607800784078807920796080008040808081208160820082408280832083608400844084808520856086008640868087208760880088408880892089609000904090809120916092009240928093209360940094409480952095609600964096809720976098009840988099209961000

Dom Hastings

Posted 2016-08-11T23:00:46.467

Reputation: 16 415

2

k4, 27

{,/"0"^(-c)$$c*1+!_x%c:#$x}

Not really golfed at all, just a straight-forward implementation of the spec.

                        $ / string
                       #  / count
                     c:   / assign to c
                   x%     / divide x by
                  _       / floor
                 !        / range (0-based)
               1+         / convert to 1-based
             c*           / multiply by count
            $             / string
       (-c)               / negative count
           $              / pad (negative width -> right-aligned)
   "0"^                   / fill blanks with zeros
 ,/                       / raze (list of string -> string)

Aaron Davies

Posted 2016-08-11T23:00:46.467

Reputation: 881

1

SQF - 164

Using the function-as-a-file format:

#define Q String""
l=(ceil log _this)+1;s='';for[{a=l},{a<=_this},{a=a+l}]do{c=([a]joinQ)splitQ;reverse c;c=(c+['0'])select[0,l];reverse c;s=format[s+'%1',c joinQ]}

Call as INTEGER call NAME_OF_COMPILED_FUNCTION

Οurous

Posted 2016-08-11T23:00:46.467

Reputation: 7 916

1

PowerShell, 77 bytes

$x="$($args[0])";$l=$x.Length;-join(1..($x/$l)|%{"$($_*$l)".PadLeft($l,'0')})

Uses string interpolation to shorten string casts. The parts before the second semicolon shorten the names of reused things. Then, every integer up to the input - and only those that are multiples of the input's length - are padded to be as long as the input string and finally joined into one.

Ben N

Posted 2016-08-11T23:00:46.467

Reputation: 1 623

1

Actually, 30 bytes

;╝R╛$l;)*@#"%0{}d"f╗`#╜%`MΣ╛@H

Try it online!

I'm not happy with the length of this code, but I'm not sure that it can be made much shorter (if at all).

Explanation:

;╝R╛$l;)*@#"%0{}d"f╗`#╜%`MΣ╛@H
;╝                              duplicate input, push a copy to reg1
  R                             range(1, input+1)
   ╛$l                          push input from reg1, stringify, length
      ;)                        duplicate and move copy to bottom of stack
        *                       multiply range by length of input
         @#                     swap range with length, make length a 1-element list
           "%0{}d"f             "%0{}d".format(length) (old-style Python format string for zero-padding integers to length of input)
                   ╗            save format string in reg0
                    `#╜%`M      for each value in range:
                     #            make it a 1-element list
                      ╜%          format using the format string
                          Σ     concatenate
                           ╛@H  take only the first (input) characters in the resulting string

Mego

Posted 2016-08-11T23:00:46.467

Reputation: 32 998

0

PHP, 83 78 bytes

<?$a=$argv[1];$i=$y=strlen($a);while($y<=$a){printf('%0'.$i.'d', $y);$y+=$i;}

Tips are more then welcome. Manage to golf it myself by one byte by changing it from a for loop to a while loop.

This code assumes that this is being execute from the command line and that $argv[1] is the int.

Thanks to:

@AlexGittemeier His suggestion (see comments) golfed this by 5 bytes to 78 bytes.

Jeroen

Posted 2016-08-11T23:00:46.467

Reputation: 210

You can change echo sprintf(...) -> printf(...) – Alex Gittemeier – 2016-08-25T15:37:39.387

0

CJam, 19 bytes

q_,:V\i,%{V+sV0e[}/

Try it online. No one has posted in CJam yet, so this is the script I used for the test cases.

Explanation

q_,:V  e# Store the length of the input as V
\i,    e# Push the range from 0 to the input
%      e# Keep only every V'th number in the array
{      e# Do this for each number:
  V+   e# Add V to get the right number of leading zeroes
  s    e# Convert to string for left padding
  V    e# Push V, the length to bring each string to, and...
  0    e# The character to add to the left
  e[   e# Left pad
}/

NinjaBearMonkey

Posted 2016-08-11T23:00:46.467

Reputation: 9 925

0

Perl 6, 69 59 46 bytes

{my \a=.chars;(a,2*a...$_).fmt("%0"~a~"s","")}

bb94

Posted 2016-08-11T23:00:46.467

Reputation: 1 831

1

You can use fmt on the list instead of map, sprintf and [~]. 42 bytes

– Jo King – 2019-03-19T04:17:20.087