# Find self-locating strings in a number

Based on this Numberphile video

A self-locating string is a number (or set of numbers) in a decimal expansion which corresponds to its location, from the start of the decimal.

For example, take the number:

.2734126393112


Here, we can identify certain items quickly, e.g:

.27 _3_ _4_ 1263 _9_ 3112


There are a few more complex cases in here though, too. For instance, the numbers 11 and 12 both appear starting in their respective positions:

.2734126393112
123456789ABCD
^
11

^
12


So the list of self-locating strings in this case would be [3, 4, 9, 11, 12], as even though some of them overlap, they both start in the correct places. If we sum these up, we get 39, or the self-reference index (SRI) of this terminating decimal.

## Input

A terminating decimal, either an array of digits (after the point) or a decimal type with 0. at the start/..

## Output

The SRI of the input number.

## Rules

• In the case that there are no self-referential numbers, the SRI is 0. This must be returned/printed, as opposed to exiting or returning undefined.
• The decimal expansion can be assumed to terminate, and will be no more than 128 digits in length.
• The counting of the indexes should be 1-based, e.g the first decimal is at position 1, etc.
• Standard I/O rules + standard loopholes apply.
• This is , so shortest answer in bytes wins

## Test cases

0.1207641728 -> 3
.12345678910 -> 55
0.1234567890112 -> 68
.0 -> 0
0.654321 -> 0
.54321 -> 3

• @JonathanAllan regarding your second comment, thanks; fixed. With your first one, the point is that your program should know to start counting after the decimal point: it needs to have a way of detecting it, the same way that when doing it with Pi you'd start counting after the three. All decimal numbers need something at the start before the point, so to make it truly general it should accept any number of digits before it. – Geza Kerecsenyi Feb 20 at 17:53
• @JonathanAllan Yes – Geza Kerecsenyi Feb 20 at 18:46
• My answer is the only one which allows there to be leading zeros in a self-locating string. The spec is not clear on this matter at present. I'd suggest allowing either handling (i.e. 0.440036 -> 6 or 9) – Jonathan Allan Feb 20 at 19:08
• Is there an implicit zero at the end? I.e. would 0.0000000001 count as 10? – Laikoni Feb 21 at 11:00
• @Laikoni No, because we're trying to keep the decimals terminating. If I allow that there'd probably be a number of other such cases to, so I'd like to just keep it to exactly the input. – Geza Kerecsenyi Feb 22 at 11:04

# Jelly,  9  8 bytes

ṫJw"Jẹ1S


A monadic Link accepting a list of the digits after the decimal point which yields an integer.

Try it online!

### How?

ṫJw"Jẹ1S - Link: list of digits, A        e.g. [3,2,1,0,5]
J       - range of length (of A)              [1,2,3,4,5]
ṫ        - tail from index (vectorises)        [[3,2,1,0,5],[2,1,0,5],[1,0,5],[0,5],[5]]
J    - range of length (of A)              [1,2,3,4,5]
"     - zip with:
w      -   first index of substring or 0     [3,1,0,0,1]
Note: w has implicit decimalisation of its right argument,
so [7,6,5,4]w65 is equivalent to [7,6,5,4]w[6,5] = 2
1  - literal one                         1
ẹ   - indexes of                          [2,5]
S - sum                                 7


# APL (Dyalog Extended), 16 bytes

+/⍬∘⍋(⍸⊣⊃¨⍕⍛⍷¨)⊂


Try it online!

Takes a string of digits.

### How it works

+/⍬∘⍋(⍸⊣⊃¨⍕⍛⍷¨)⊂  ⍝ Input: character vector of digits
⍬∘⍋             ⍝ X←Array of 1-based indices
(    ⍕⍛ ¨)   ⍝ Stringify each of X
(      ⍷¨)⊂  ⍝ And for each of above, build a boolean array where
⍝   substring matches are marked as 1
⍝ e.g. '10'⍷'10428104' is [1 0 0 0 0 1 0 0]
⊣⊃¨        ⍝ Extract X-th indices from each of above
⍸           ⍝ Convert ones to its 1-based locations
+/                ⍝ Sum


āʒ.$yÅ?}O  Try it online! • Didn't know you could vote on deleted answers. And comment. – ouflak Feb 20 at 18:12 • @ouflak I really don't think you can, actually. – Grimmy Feb 20 at 18:15 • 9 bytes if you use the same input style as this answer? – Expired Data Feb 21 at 10:34 # PowerShell, 60 56 bytes param($n)1..128|%{$o+=$_*($_-eq$n.indexOf("$_",$_))};+$o  Try it online! Takes input $n as a string (else you'll get floating point inaccuracies), then constructs a range from 1 to 128. We then loop through those numbers (the |%{...}) and each iteration we're accumulating into $o the current number times if the current number $_ is -equal to the .indexOf the current number "$_" starting at position $_ in the input string $n. In other words, if the current number matches the first index starting at that position, the current number is added to our output. After the loop, we tack on a + at the front to account for the zero case (i.e., no numbers in the collection). That result is left on the pipeline and output is implicit. -4 bytes thanks to inspiration from ElPedro. • Very nice. I'm trying to learn Powershell at the moment. Guess I won't be allowed to write stuff like this at work ;) – ElPedro Feb 20 at 19:19 • @ElPedro No. Do not. lol Just like any good golfing answer, people on Code Review would have a heart attack. codegolf.stackexchange.com/questions/191/… – AdmBorkBork Feb 20 at 19:23 • If Powershell had been around in the really early days of Windows we would have to do this kinda thing with only 64k of memory available but then, who would ever need more than 64k? :) Guess I'm showing my age now. – ElPedro Feb 20 at 19:28 • @ElPedro lol, thanks for the inspiration! Reminding me of that trick saved 4 bytes here. – AdmBorkBork Feb 20 at 19:33 • @mazzy That doesn't perform the summation, which is the required output. – AdmBorkBork Feb 21 at 13:53 # R, 1̶0̶2̶, 99 bytes Thanks to @Giuseppe for 99 bytes U=[ [=Map sum(which(paste0[U[list(x<-scan()),+[(L=seq(x))-1,seq[nchar(L)]]],collapse=""]==L))  Try it online! Few bytes can be saved if there is a second 2-byte 3-argument operator like [. First time messing with [, it is fun. • 99 bytes from your original; it took forever to unpack to see if there was a different golf for operator aliasing, and I still came up basically empty. – Giuseppe Feb 20 at 20:40 • I'm not sure your latest edit works, since it doesn't do the sum? – Giuseppe Feb 20 at 20:40 • @Giuseppe I broke it. Fixed now. My head hurts reading this code. – Vlo Feb 20 at 20:43 • mine too, if that's any consolation! – Giuseppe Feb 20 at 20:43 • 74 bytes doing a string-manipulation approach; I think there are some bytes to shave off of that too... – Giuseppe Feb 20 at 20:48 # JavaScript (ES6), 50 48 bytes Takes input as a string. A recursive approach. f=(s,n=1)=>s?+s.match('^'+n)+f(s.slice(1),n+1):0  Try it online! s.match('^'+n) is either null or a singleton array holding $$\n\$$ as a string. By applying the unary +, these values are coerced to $$\0\$$ or $$\n\$$ respectively. # JavaScript (ES6), 52 bytes Takes input as a string. s=>[...s].reduce(t=>t+!(i-s.indexOf(i+1,i))*++i,i=0)  Try it online! # Python 2, 112 $$\\cdots\$$ 52 51 bytes Saved 9 bytes thanks to ElPedro!!! Saved a byte thanks to Jonathan Allan!!! Saved 3 4 bytes thanks to Poon Levi!!! f=lambda s,i=0:s>s[:i]and(s[:i]+iin s)*i+f(s,i+1)  Try it online! Takes a number in the form .abc... as string input and returns its SRI. • You can simplify a bit now since input restriction has been relaxed. – Jonathan Allan Feb 20 at 18:09 • @JonathanAllan Well done, that floating decimal point was costly! :-) – Noodle9 Feb 20 at 18:25 • Save 1: sum(i*(s.find(i,i)==i)for... – Jonathan Allan Feb 20 at 21:32 • -3: sum(i*(s[:i]+iin s)... – Poon Levi Feb 21 at 11:16 • You can further shave off 1 byte by doing s>s[:i] instead of i<len(s) – Poon Levi Feb 21 at 18:48 # J, 30 29 bytes 1#.#\(=#])(<:,:#@":)@#\".;.0,  Try it online! # Ruby, 46 44 bytes ->n{r=0;n.chars.sum{n[r+=1,r]=~/^#{r}/?r:0}}  Try it online! Thanks Value Ink, as usual, for -2 bytes. • With the power of sheer insanity-- uh I mean boredly checking if I could make the first argument of a slice use += without throwing a syntax error, I have found a 44 byte solution – Value Ink Feb 22 at 3:02 # Perl 5-pl, 27 bytes Requires input to be in the format .####...: $\+=++$a*/\G$a/ while/./g}{


Try it online!

$/.from # To their position in the string  # Retina 0.8.2, 29 bytes  ¶$.$.$*;$'¶ Gm^(.+);+\1 ;  Try it online! Link includes test cases. Assumes input begins with the decimal point. Explanation:  ¶$.$.$*;$'¶  For each offset in the string, list the offset in decimal, then again in unary, then the suffix starting at that offset, wrapping the whole thing in newlines so that the characters in the input string don't contaminate the data. Gm^(.+);+\1  Keep only the lines where the suffix starts with the offset. ;  Take the total of the matching unary offsets. # Charcoal, 18 bytes ＩΣＥＬθ×ι⁼Ｉι✂θι⁺ιＬＩι  Try it online! Link is to verbose version of code. Assumes input begins with the decimal point. Explanation:  θ Input string Ｌ Length Ｅ Map over implicit range ι Current index Ｉ Cast to string Ｌ Length ι Current index ⁺ Added ι Current index θ Input string ✂ Sliced ι Current index Ｉ Cast to string ⁼ Equals ι Current index × Multiplied Σ Take the sum Ｉ Cast to string for implicit print  # Haskell, 71 bytes import Data.List f l=sum[i|(i,x)<-zip[0..]$tails l,show iisPrefixOfx]


Try it online!

# Java 8, 86 bytes

s->{int r=0,i=0;for(;i<s.length();)r+=s.substring(i++).startsWith(i+"")?i:0;return r;}


To the point approach. Will see if I can find something shorter later on. Also, this is probably the first time I've used startsWith in Java (either in or outside codegolfing). ;)

Input as a String.

Try it online.

Explanation:

s->{                       // Method with String parameter and integer return-type
int r=0,                 //  Result-sum, starting at 0
i=0;for(;i<s.length();)  //  Loop i in the range [0,input-length):
r+=                    //   Increase the result-sum by:
s.substring(i++)    //    Take the substring of the input, starting at index i
//    And increase i by 1 afterwards with i++
.startsWith(i+"")? //    If this substring starts with i (converted to String):
i                //     Increase the result-sum by i
:                 //    Else:
0;               //     Leave the result-sum the same by increasing with 0
return r;}               //  And return the sum as result


# Python 2, 64 60 bytes

lambda i:sum(x for x in range(len(i))ifx==i[x:x+len(x)])


Try it online!

The 0 result works because an empty list in Python is equivalent to False which is equivalent to 0 and when you sum(0) you very conveniently get 0.

• You can use find now, I've been shown another way. – Noodle9 Feb 21 at 11:45
• @Noodle9 Thanks but I'll probably leave it as it is now. – ElPedro Feb 21 at 12:30

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

a=>Enumerable.Range(1,a.Length).Sum(x=>a.Remove(0,x).StartsWith(x+"")?x:0)


Try it online!

# T-SQL, 103 bytes

SELECT number+1FROM spt_values
WHERE type='P'and-~number=substring(concat(@,''),number+3,len(number+1))


Try it online

# Zsh, 43 bytes

repeat $#1 ((r+=0${(M)1[++i,-1]#$i})) <<<$r


Try it online!

Takes input as a string. Repeatedly (M)atches the part of the string string at position ++i to -1 that #starts with $i, and adds it to $r. The 0 ensures that a valid number is added in the case of no match, so $r is set to a value before being printed. # Python 2, 53 bytes f=lambda s,i=0:s>''and(s.find(i)==0)*i+f(s[1:],i+1)  A recursive version of a previous version of Noodle9's Python 2 answer. Try it online! • I've taken a leaf out of your book and gone recusive with a new devilish test unleashed by @PoonLevi! 😈 – Noodle9 Feb 21 at 13:37 # PowerShell, 49 bytes [Double] has 15 to 17 significant decimal digits precision, so we can consider a finite number of digits param($n)1..99|%{$s+=$_*($n-match"^.{$_}$_")} +$s


Try it online!

# PowerShell, 54 bytes

any string representation of decimal number

param($n)$n|% t*y|%{$s+=++$i*($n-match"^.{$i}$i")} +$s


Try it online!

• Fixed. Thanks!. – mazzy Feb 21 at 16:27

# Japt-x, 12 bytes

ÊÇ¥UtZZsl¹*Z


Try it online!