Take the 2-minute tour ×
Programming Puzzles & Code Golf Stack Exchange is a question and answer site for programming puzzle enthusiasts and code golfers. It's 100% free, no registration required.

Without using strings (except when necessary, such as with input or output) calculate the nth digit, from the left, of an integer (in base 10).

Input will be given in this format:

726433 5

Output should be:

3

as that is the fifth digit of "726433".

Input will not contain leading zeros, e.g. "00223".

Test cases / further examples:

9 1  ->  9
0 1  ->  0
444494 5  ->  9
800 2  ->  0

This is code golf; least amount of characters wins, but any built in functions such as "nthDigit(x,n)" are not acceptable.

Here's some pseudo-code to get you started:

x = number
n = index of the digit
digits = floor[log10[x]] + 1
dropRight = floor[x / 10^(digits - n)]
dropLeft = (dropRight / 10 - floor[dropRight / 10]) * 10
nthDigit = dropLeft

As you can see I'm new to code golf, and though I think it's a bit unfair that I ask a question before I've even answered one, I would really like to see what kind of responses this generates. :)

Edit: I was hoping for mathematical answers, so I cannot really accept answers that rely on converting strings to arrays or being able to access numbers as a list of digits.

We have a winner

Written in "dc", 12 bytes. By DigitalTrauma.

share|improve this question
    
Can this be just a function or must it need to handle I/O? If it does not need to handle I/O can it simply be a lambda instead of a function? –  slebetman Apr 9 at 6:15
    
Your edit leaves it unclear as to what exactly you don't like. In particular, with "being able to access numbers as a list of digits", is it the use of arrays in any form that you don't like, or just the existence of built-in base conversion routines? –  Peter Taylor Apr 9 at 8:44
    
@PeterTaylor Arrays of digits are not OK, as one can easily just grab the nth item in the array. I am not sure how base-conversion works exactly, but it seems to easy. –  kukac67 Apr 9 at 15:45
    
Why is it a problem to build a list of digits? That is highly mathematical - it represents the number as a polynomial. –  2rs2ts Apr 9 at 16:03
    
@2rs2ts If you can create a list of digits mathematically, i.e. without parsing a string into an array, then it could be acceptable. –  kukac67 Apr 9 at 16:10
show 3 more comments

28 Answers 28

up vote 1 down vote accepted

dc, 12 bytes

?dZ?-Ar^/A%p

This is a mathematical answer. Here's how it works:

  • ? read input number and push to stack
  • d duplicate top of stack
  • Z Pops value off the stack, calculates and pushes the number of digits
  • ? read digit index and push to stack
  • - subtract digit index from digit count
  • A push 10 to the stack
  • r swap top 2 values on stack
  • ^ exponentiate 10 ^ (digit count - digit index)
  • / divide number by result of exponentiation
  • A push 10 to the stack
  • % calculate the number mod 10 to get the last digit and push to top of stack
  • p pop and print the top of stack

In action:

$ { echo 987654321; echo 1; } | dc ndigit.dc
9
$ { echo 987654321; echo 2; } | dc ndigit.dc
8
$ { echo 987654321; echo 8; } | dc ndigit.dc
2
$ { echo 987654321; echo 9; } | dc ndigit.dc
1
$ 
share|improve this answer
1  
I think you're the winner. This is the third shortest code, but the shortest 2 used base conversion -> arrays. –  kukac67 Apr 13 at 19:23
add comment

GolfScript (10 bytes)

~(\10base=

This assumes input is as a string (e.g. via stdin). If it's as two integers on the stack, the initial ~ should be removed, saving 1 char.

If the base conversion is considered to fall foul of the built-in functions rule, I have a 16-char alternative:

~~)\{}{10/}/=10%
share|improve this answer
    
Your first program with the base conversion outputs the first digit only if you enter "0" and the second if you enter "1". golfscript.apphb.com/?c=MjcwNiAxCgpcMTBiYXNlPQ%3D%3D –  kukac67 Apr 8 at 23:52
    
@kukac67, fixed. –  Peter Taylor Apr 9 at 8:32
add comment

J - 15 24 char

A sufficiently "mathematical answer".

(10|[<.@*10^]-10>.@^.[)/

Same results as below, but is endowed with the mystical quality of being mathematical.


The short version, using base-10 expansion.

({0,10&#.inv)~/

We prepend a 0 to adjust for 1-based indexing.

Usage:

   ({0,10&#.inv)~/ 1234567 3
3
   ({0,10&#.inv)~/ 444494 5
9
share|improve this answer
2  
Strings are not allowed. –  caffinatedmonkey Apr 8 at 23:27
add comment

Haskell 60 bytes and readable

nth x n
        | x < (10^n) = mod x 10
        | True = nth (div x 10) n

no strings involved!

*Main> nth 1234567 4
4
share|improve this answer
add comment

C, 50

This uses arrays.

main(int c,char**a){putchar(a[1][atoi(a[2])-1]);}

Just ignore all the warnings.

And yes, in C, strings are really just arrays, so this is sort of cheap.


More Mathematical:

C, 83

main(int c,char**a){printf("%d",(atoi(a[1])/pow(10,strlen(a[1])-atoi(a[2])))%10);}
share|improve this answer
    
isn't it using string/array functions? –  V-X Apr 10 at 5:20
    
First one does, like it says ;) The second one obviously doesn't, apart from the strlen, which I chose simply because it's shorter than using log. If that's a problem it's an easy fix, I can add it when I get home. –  SBI Apr 10 at 6:46
    
There we go, added the purely mathematical version. –  SBI Apr 11 at 8:56
2  
Math - not even once! –  Potzblitz Apr 11 at 8:59
add comment

bc (driven by bash), 41 29

I think this is the first answer to do this mathematically and not with strings:

bc<<<"$1/A^(length($1)-$2)%A"

The use of length() perhaps seems a bit stringy, but the bc man page talks about number of digits and not length of string:

  length ( expression )
          The value of the length function is the  number  of  significant
          digits in the expression.

Output:

$ ./ndigits.bc.sh 726433 5
3
$ ./ndigits.bc.sh 9 1
9
$ ./ndigits.bc.sh 0 1
0
$ ./ndigits.bc.sh 444494 5
9
$ ./ndigits.bc.sh 800 2
0
$ 
share|improve this answer
1  
@kukac67 I appreciate the acceptance vote! But I think it is customary for code-golf questions to be left open more than 2 hours to encourage more answers. Perhaps a week or so. I won't be offended if you de-accept this answer :) –  DigitalTrauma Apr 9 at 1:38
1  
ok. I will de-accept then. Hope you don't win! :P –  kukac67 Apr 9 at 2:59
add comment

Python 127

def f(i,n):
 b=10;j=i/b;k=1;d=i-j*b
 while j>0:
  k+=1;j/=b
 if n>k:
  return -1
 while k>n:
  k-=1;j/=b;i/=b;d=i-j*b
 return d
share|improve this answer
    
You don't need to define it as a fn: def f(i,n): ... return d –  smci Apr 9 at 10:44
    
You don't need to sanity-check the if n>k: return -1 case. –  smci Apr 9 at 10:45
    
...and you certainly don't need to make a first-pass just to count k (the number of digits in i), in order to sanity-compare it to n. –  smci Apr 9 at 10:52
add comment

Mathematica - 24 23

This one is kind of obvious :)

IntegerDigits[#][[#2]]&

Example:

IntegerDigits[#][[#2]]& [726433, 5]

Output:

3

You can get it shorter by hard-coding two integers, e.g.

IntegerDigits[n][[m]]

but then you first have to write n = 726433; m = 5;. The function call felt more similar to a program.

share|improve this answer
1  
You can drop the number 1. –  David Carraher Apr 9 at 13:53
    
Thank you @DavidCarraher :-) –  CompuChip Apr 9 at 14:31
    
Now this is cheating.. :D –  kukac67 Apr 9 at 15:46
add comment

C 145

Program finds distance from end of integer and divides until index is reached then uses modulus 10 to get the last digit.

int main()
{
int i,a,b,d,n;
scanf("%d %d",&i,&a);
d=(int)(log(i)/log(10))+1;
n=d-a;
while(n--){i=(int)(i/10);}
b=i%10;
printf("%d",b);
}
share|improve this answer
    
This can be golfed significantly. Start with these tips –  DigitalTrauma Apr 9 at 23:20
    
For a start, the (int) casts and associated parens are unnecessary –  DigitalTrauma Apr 9 at 23:36
1  
I couldn't resist. I golfed it down to 87 chars: i,a;main(){scanf("%d%d",&i,&a);for(a=log(i)/log(10)+1-a;a--;)i/=10;printf("%d",‌​i%10);}. –  DigitalTrauma Apr 9 at 23:37
add comment

Wolfram Alpha - between 40 and 43

Of course, I can totally defend that using IntegerDigits is a trick that does not fall under

any built in functions such as "nthDigit(x,n)"

But because my previous answer still felt like cheating a little bit, here's an alternative. Unfortunately it's quite a bit longer, but I didn't see how to shorten it any more than I did.

Counting in a similar way as before (with the ampersand, without passing in any arguments),

Mod[Trunc[#/10^(Trunc[Log10[#]]-#2+1)],10]&

has 43 characters. By negating the exponent and shuffling the terms around, I can lose one arithmetic operator (10^(...)x will be interpreted as multiplication)

Mod[Trunc[10^(#2-Trunc[Log10[#]]-1)#],10]&

I don't have Mathematica at hand to test, I doubt that it will beAs I suspected (and as was kindly verified by kukac67) in Mathematica this is not accepted, but it runs in WolframAlpha.

I am in doubt about the use of RealDigits, because I restricted myself from using IntegerDigits for this answer and they are quite similar. However, if I allow myself to include it (after all, it doesn't return the integers directly, just how many of them there are), I can slash off another two characters:

Mod[Trunc[10^(#2-RealDigits[#]-1)#],10]&
share|improve this answer
    
I tried it in Mathematica, it doesn't output a value. The 43 character one ouputs this: Mod[Trunc[57 2^(3 - Trunc[Log[456]/Log[10]])5^Trunc[Log[456]/Log[10]]], 10] –  kukac67 Apr 9 at 16:26
    
Yeah, I figured as much. Wolfram Alpha is a bit more lenient in interpreting input. Luckily I gave it the correct header ;) –  CompuChip Apr 9 at 16:29
    
But I see it does work on WolframAlpha. –  kukac67 Apr 9 at 16:30
    
{edit} Although I see the link is broken... apparently doesn't like [ characters even when they are encoded. I'll pull it through an URL shortener. {edit2} Apparently W.Alpha has one - changed the link. –  CompuChip Apr 9 at 16:30
add comment

Tcl (42 bytes, lambda):

{{x y} {expr $x/10**int(log10($x)+1-$y)%10}}

(49 bytes, function):

proc f {x y} {expr $x/10**int(log10($x)+1-$y)%10}

(83 bytes, if we need to accept input from shell):

puts [expr [lindex $argv 0]/10**int(log10([lindex $argv 0])+1-[lindex $argv 1])%10]
share|improve this answer
    
How does this work? –  kukac67 Apr 9 at 16:08
    
Added explanation. It's just the most obvious way to do it mathematically. How you'd do it on paper. –  slebetman Apr 9 at 17:11
    
I think you're counting from the wrong end. –  Peter Taylor Apr 9 at 17:18
    
Hmm.. yeah. Looks like it. I'll revise it to count form the left. –  slebetman Apr 9 at 17:20
    
I'll accept the 31 bytes. Though how can the lambda be run? Does Tcl have an interpreter which can use it? Or only as part of a program which defines the arguments? –  kukac67 Apr 9 at 17:32
show 1 more comment

CJam - 7

l~(\Ab=

CJam is a new language I am developing, similar to GolfScript - http://sf.net/p/cjam. Here is the explanation:

l reads a line from the input
~ evaluates the string (thus getting the two numbers)
( decrements the second number
\ swaps the numbers
A is a variable preinitialized to 10
b does a base conversion, making an array with the base-10 digits of the first number
= gets the desired element of the array

The program is basically a translation of Peter Taylor's solution.

share|improve this answer
    
I would argue putting base 10 digits into an array is more of a string operation than a mathematical one. –  DigitalTrauma Apr 12 at 21:08
add comment

Scala (133 99 bytes):

Works for all positive inputs. Divides by 10 to the power of the digit looked for from the right, then takes it modulo 10.

def k(i:Array[String])={val m=i(0).toInt
(m*Math.pow(10,i(1).toInt-1-Math.log10(m)toInt)).toInt%10}

Thank you for noticing the bug in the previous formula. This one is shorter.

share|improve this answer
    
I like it! :) Up-voted –  kukac67 Apr 9 at 16:01
    
Tested the solution: k(Array("1234", "7")) which gives 9. Does it not work for n > #digits(x) ? –  lambruscoAcido Apr 9 at 20:48
    
It's because 10^-1 is not exact in this notation, so there is a rounding error when you take 10%pow(10,-1) which should have given zero but gave 0.0999 instead. Corrected my answer to accomodate this side-effect. –  Mikaël Mayer Apr 10 at 6:04
add comment

Haskell, 142

I'm not sure I understood the question correctly, but this is what I think you wanted: read stdin (string), make the two numbers int (not string), do some algorithmic things, and then output the result (string). I crammed it into 142 chars, which is way too much:

import System.Environment
a%b|a>9=div a 10%(b+1)|1<2=b
x#n=x`div`10^(x%1-n)`mod`10
u[a,b]=read a#read b
main=fmap(u.words)getContents>>=print

example usage:

> echo 96594 4 | getIndex
9
share|improve this answer
add comment

JavaScript - 84

p=prompt,x=+p(),m=Math;r=~~(x/m.pow(10,~~(m.log(x)/m.LN10)+1-+p()));p(r-~~(r/10)*10)

Purely mathematical, no strings, none of them. Takes the first number in the first prompt and the second number in the second prompt.

Test Case:

Input: 97654 5
Output: 4

Input: 224658 3
Output: 4

Ungolfed Code:

p = prompt,
x = +p(), // or parseInt(prompt())
m = Math;

r = m.floor( x / m.pow(10, m.floor(m.log(x) / m.LN10) + 1 - +p()) )
//                                               ^-- log(10) ^-- this is `n`

p(r - ~~(r / 10) * 10) // show output
share|improve this answer
add comment

perl, 38, 36   no 30 characters

(not counting the linefeed)

This is arguably cheating due to the command switch, but thanks for letting me play :-)

~/$ cat ndigits.pl
say((split//,$ARGV[0])[$ARGV[1]-1]);
~/$ tr -cd "[:print:]" < ndigits.pl |wc -m 
36
~/$ perl -M5.010 ndigits.pl 726433 5 
3

edit:

Was able to remove 2 characters:

 say for(split//,$ARGV[0])[$ARGV[1]-1];
 say((split//,$ARGV[0])[$ARGV[1]-1]);

... then 6 more:

 say((split//,shift)[pop()-1]);

How

We split the input of the first argument to the script $ARGV[0] by character (split//) creating an zero indexed array; adding one to the second argument $ARGV[1] to the script then corresponds to the element at that position in the string or first argument. We then hold the expression inside () as a one element list which say will iterate through. For the shorter short version we just shift in the first argument and use the remaining part of @ARGV to use for the index - once shifted only the second argument remains so we pop() it and subtract 1.

Is this supposed to be a math exercise? I just realized I'm indexing a string read from input, so ... I guess I lose?? Mark me up if I make sense in parallel golf course and I will try again - more mathematically - in a separate answer.

cheers,

share|improve this answer
    
Yup, sorry, Without using strings. Welcome to PPCG anyway! –  DigitalTrauma Apr 12 at 2:47
    
OK sorry 'bout that ... so far my mathematical approaches are not very golf-worthy :-) –  G. Cito Apr 12 at 14:08
add comment

PHP, 58

Using math only

<?$n=$argv[1];while($n>pow(10,$argv[2]))$n/=10;echo $n%10;

share|improve this answer
1  
Doesn't this find from the right? –  Trimsty Apr 9 at 14:58
2  
You can save 1 char by changing it to echo$n%10. –  Amal Murali Apr 9 at 19:41
    
@Trimsty no, it actually loops until entered number is no longer bigger than 10^x, x being the digit number. So, for example, if you enter 3457 as a number and 2 as a digit, it will take away the last digit until the number becomes smaller than 100 (10^2). That means it will take away 5 and 7, because then 34 remains and it is not bigger than 100. Then it just outputs the last digit (4). –  DKasipovic Apr 9 at 19:44
    
But it is true that if the second number is bigger than the number of digits, you output 9 and not zero –  Mikaël Mayer Apr 10 at 6:26
    
I see, it outputs last digit if the number if bigger than the number of digits. If you enter 1234 and 5th digit, you will get 4 since 1234 i already less than 10^5. –  DKasipovic Apr 10 at 6:53
add comment

~-~! - 94 93

Bends the rules a bit - it's a function that takes n as input and assumes the number to find digit n of is stored in ''''' - and ~-~! doesn't support floats.

'=~~~~~,~~:''=|*==~[']<''&*-~>,'|:'''=|*==%[%]~+*/~~~~/~~|:''''=|'''''/''&<<'''&'''''>-*-~>|:

'''''=~~~~,~~,~~,~~,~~,~~:''''''=''''&~: will result in '''''' being ~~ (2) (''''' = 128).

share|improve this answer
    
Hm... Yet another esoteric language? –  VisioN Apr 9 at 14:33
    
@VisioN it isn't really esoteric, just that the only native data type is a number and it can't interact with the os/internet. esolangs.org/wiki/No_Comment –  Trimsty Apr 9 at 14:34
1  
Well, to me every syntax that can't be easily read by a human being is esoteric. And yes, Perl is also esoteric according to this theory :) –  VisioN Apr 9 at 14:38
    
@VisioN It gets easy to read after a while. :P –  Trimsty Apr 9 at 14:45
add comment

Python 2.7 (89 bytes)

I transform the integer into a "polynomial" by using a list of digits. I know you say you can't accept that, but I don't see why not since it uses the mathematical concept of numbers being represented as polynomials of their bases. It will only fail when the integer passed in is 0, but you said no padded zeroes ;)

import sys;v=sys.argv;p,x,n=[],int(v[1]),int(v[2])
while x:p=[x%10]+p;x//=10
print p[n-1]

Run as test.py:

$ python test.py 726489 5
8

I assume you wanted shell input and that I couldn't make use of the fact that the input would be strings. Skipping shell input it's just 43 bytes, with:

p=[]
while x:p=[x%10]+p;x//=10
print p[n-1]

Although I use some unnecessary iteration, I save some bytes by not adding an additional decrement on n.

share|improve this answer
add comment

Extended BrainFuck: 49

+[>>,32-]<<-[<<-],49-[->>>[>>]+[<<]<]>>>[>>]<33+.

Usage:

% bf ebf.bf < nth-digit.ebf > nth-digit.bf
% echo "112234567 7" | bf nth-digit.bf 
5

I'm not ectually using any special features of EBF except the multiplication operator (eg. 10+ => ++++++++++). Other than that it's mostly pure BrainFuck

How it works:

+                ; Make a 1 in the first cell
[>>,32-]         ; while cell is not zero: read byte 2 to the right and reduce by 32 (space)
<<-[<<-]         ; move back to the first cell by reducing every cell with 1
,49-             ; read index, reduce by 49 so that ascii 1 becomes 0
[->>>[>>]+[<<]<] ; use that to fill a trail of breadcrumbs to the desired number
>>>[>>]          ; follow the breadcrumbs
<33+.            ; go to value part, increase by 33 (32 + 1 which we substracted) and print

Scheme (R6RS): 100 (without unnecessary whitespace)

(let*((x(read))(n(read))(e(expt 10(-(floor(+(/(log x)(log 10))1))n))))
  (exact(div(mod x(* e 10))e)))
share|improve this answer
add comment

awk - 53

{for(d=10^9;!int($1/d)||--$2;d/=10);$0=int($1/d)%10}1
  1. trim digits by division, starting with max possible for 32 bit unsigned int
  2. when we hit the left side of the integer, int($1 / d) returns non-zero
  3. continue n ($2) digits past that

Ungolfed:

{
    for(d = 1000000000; int($1 / d) != 0 || --$2; d /= 10);
    print int($1 / d) % 10;
}
share|improve this answer
add comment

R (60)

Solved the problem using log10 to calculate the number of digits. The special case x==0 costs 13 character, sigh.

f=function(x,n)if(x)x%/%10^(trunc(log10(x))-n+1)%%10 else 0

Ungolfed:

f=function(x,n)
  if(x) 
    x %/% 10^(trunc(log10(x)) - n + 1) %% 10
  else
    0

Usage

> f(898,2)
[1] 9
share|improve this answer
add comment

Scala (83)

Does not use any Scala special features. Rather the standard solution.

def f(x:Int,n:Int)=if(x==0)0 else x/(math.pow(10,math.log10(x).toInt-n+1)).toInt%10

Ungolfed:

def f(x:Int,n:Int) = 
  if(x==0)
    0
  else
    x / (math.pow(10, math.log10(x).toInt - n + 1)).toInt % 10 
share|improve this answer
add comment

C, 94

main(x,y,z,n){scanf("%d%d",&x,&y);for(z=x,n=1-y;z/=10;n++);for(;n--;x/=10);printf("%d",x%10);}

C, 91, invalid because of using arrays.

main(x,y,z){int w[99];scanf("%d%d",&x,&y);for(z=0;x;x/=10)w[z++]=x%10;printf("%d",w[z-y]);}
share|improve this answer
    
I disallowed arrays in a edit (before you posted this)... But I like how you did this. :) –  kukac67 Apr 9 at 15:52
    
OK, I wasn't looking properly. I've added a solution avoiding arrays. –  V-X Apr 10 at 5:18
add comment

Julia 37

d(x,y)=div(x,10^int(log10(x)-y+1))%10

Owing to the builtin ^ operator. Arbitrary precision arithmetic allows for any size int.

Sample

julia> d(1231198713987192871,10)
3
share|improve this answer
add comment

perl (slightly more mathy/not very golfy) - 99 chars

 ~/$ cat ndigits2.pl
  ($n,$i)=@ARGV;
  $r=floor($n/10**(floor(log($n)/log(10)+1)-$i));
  print int(.5+($r/10-floor($r/10))*10);

Run it as:

 perl -M5.010 -MPOSIX=floor ndigits.pl 726433 1
share|improve this answer
add comment

Perl6 - 85 chars

my ($n,$i)=@*ARGS;
my$r=$n/10**(log10($n).round-$i);
say (($r/10-floor($r/10))*10).Int;
share|improve this answer
add comment

Smalltalk, 44

Although dc is unbeatable, here is a Smalltalk solution:

arguments, n number; d digit-nr to extract:

[:n :d|(n//(10**((n log:10)ceiling-d)))\\10]
share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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