Middle three digits

From Rosetta Code
Revision as of 00:57, 4 February 2013 by Tikkanz (talk | contribs) (→‎{{header|J}}: fix reference to len and simplify)
Task
Middle three digits
You are encouraged to solve this task according to the task description, using any language you may know.

The task is to:

Write a function/procedure/subroutine that is called with an integer value and returns the middle three digits of the integer if possible or a clear indication of an error if this is not possible.

Your function should be tested with the following values; the first line should return valid answers, those of the second line should return clear indications of an error:

123, 12345, 1234567, 987654321, 10001, -10001, -123, -100, 100, -12345
1, 2, -1, -10, 2002, -2002, 0

Show your output on this page.

D

<lang d>import std.stdio, std.traits, std.conv;

string middleThreeDigits(T)(in T n) if (isIntegral!T) {

   auto s = n < 0 ? n.text()[1 .. $] : n.text();
   auto len = s.length;
   if (len < 3 || len % 2 == 0)
       return "Need odd and >= 3 digits";
   auto mid = len / 2;
   return s[mid - 1 .. mid + 2];

}

void main() {

   immutable passing = [123, 12345, 1234567, 987654321, 10001, -10001,
           -123, -100, 100, -12345, long.min, long.max];
   immutable failing = [1, 2, -1, -10, 2002, -2002, 0, int.min, int.max];
   foreach (n; passing)
       writefln("middleThreeDigits(%s): %s", n, middleThreeDigits(n));
   foreach (n; failing)
       writefln("middleThreeDigits(%s): %s", n, middleThreeDigits(n));

}</lang>

middleThreeDigits(123): 123
middleThreeDigits(12345): 234
middleThreeDigits(1234567): 345
middleThreeDigits(987654321): 654
middleThreeDigits(10001): 000
middleThreeDigits(-10001): 000
middleThreeDigits(-123): 123
middleThreeDigits(-100): 100
middleThreeDigits(100): 100
middleThreeDigits(-12345): 234
middleThreeDigits(-9223372036854775808): 368
middleThreeDigits(9223372036854775807): 368
middleThreeDigits(1): Need odd and >= 3 digits
middleThreeDigits(2): Need odd and >= 3 digits
middleThreeDigits(-1): Need odd and >= 3 digits
middleThreeDigits(-10): Need odd and >= 3 digits
middleThreeDigits(2002): Need odd and >= 3 digits
middleThreeDigits(-2002): Need odd and >= 3 digits
middleThreeDigits(0): Need odd and >= 3 digits
middleThreeDigits(-2147483648): Need odd and >= 3 digits
middleThreeDigits(2147483647): Need odd and >= 3 digits

Alternative Version

This longer version gives a stronger typed output, and it tries to be faster avoiding conversions to string. <lang d>import std.stdio, std.traits, std.math, std.variant;

/// Returns a string with the error, or the three digits. Algebraic!(string, char[3]) middleThreeDigits(T)(in T n) if (isIntegral!T) {

   // Awkward code to face abs(T.min) when T is signed.
   ulong ln;
   static if (isSigned!T) {
       if (n >= 0) {
           ln = n;
       } else {
           if (n == T.min) {
               ln = -(n + 1);
               ln++;
           } else {
               ln = -n;
           }
       }
   } else {
       ln = n;
   }
   if (ln < 100)
       return typeof(return)("n is too short.");
   immutable uint digits = 1 + cast(uint)log10(ln);
   if (digits % 2 == 0)
       return typeof(return)("n must have an odd number of digits.");
   // From the Reddit answer by "millstone".
   int drop = (digits - 3) / 2;
   while (drop-- > 0)
       ln /= 10;
   char[3] result = void;
   result[2] = ln % 10 + '0';
   ln /= 10;
   result[1] = ln % 10 + '0';
   ln /= 10;
   result[0] = ln % 10 + '0';
   return typeof(return)(result);

}

void main() {

   immutable passing = [123, 12345, 1234567, 987654321, 10001,
                        -10001, -123, -100, 100, -12345, -8765432];
   foreach (n; passing) {
       auto mtd = middleThreeDigits(n);
       // A string result means it didn't pass.
       assert(!mtd.peek!string);
       writefln("middleThreeDigits(%d): %s", n, mtd);
   }
   writeln();
   immutable failing = [1, 2, -1, -10, 2002, -2002, 0,
                        15, int.min, int.max];
   foreach (n; failing) {
       auto mtd = middleThreeDigits(n);
       assert(mtd.peek!string);
       writefln("middleThreeDigits(%d): %s", n, mtd);
   }
   writeln();
   immutable long[] passingL = [123, 12345, 1234567, 987654321, 10001,
                                -10001, -123, -100, 100, -12345,
                                -8765432, long.min, long.max];
   foreach (n; passingL) {
       auto mtd = middleThreeDigits(n);
       assert(!mtd.peek!string);
       writefln("middleThreeDigits(%d): %s", n, mtd);
   }
   writeln();
   immutable long[] failingL = [1, 2, -1, -10, 2002, -2002, 0, 15];
   foreach (n; failingL) {
       auto mtd = middleThreeDigits(n);
       assert(mtd.peek!string);
       writefln("middleThreeDigits(%d): %s", n, mtd);
   }
   writeln();
   {
       immutable n = short.min;
       auto mtd = middleThreeDigits(n);
       assert(!mtd.peek!string);
       writefln("middleThreeDigits(cast(short)%d): %s", n, mtd);
   }

}</lang>

Output:
middleThreeDigits(123): 123
middleThreeDigits(12345): 234
middleThreeDigits(1234567): 345
middleThreeDigits(987654321): 654
middleThreeDigits(10001): 000
middleThreeDigits(-10001): 000
middleThreeDigits(-123): 123
middleThreeDigits(-100): 100
middleThreeDigits(100): 100
middleThreeDigits(-12345): 234
middleThreeDigits(-8765432): 654

middleThreeDigits(1): n is too short.
middleThreeDigits(2): n is too short.
middleThreeDigits(-1): n is too short.
middleThreeDigits(-10): n is too short.
middleThreeDigits(2002): n must have an odd number of digits.
middleThreeDigits(-2002): n must have an odd number of digits.
middleThreeDigits(0): n is too short.
middleThreeDigits(15): n is too short.
middleThreeDigits(-2147483648): n must have an odd number of digits.
middleThreeDigits(2147483647): n must have an odd number of digits.

middleThreeDigits(123): 123
middleThreeDigits(12345): 234
middleThreeDigits(1234567): 345
middleThreeDigits(987654321): 654
middleThreeDigits(10001): 000
middleThreeDigits(-10001): 000
middleThreeDigits(-123): 123
middleThreeDigits(-100): 100
middleThreeDigits(100): 100
middleThreeDigits(-12345): 234
middleThreeDigits(-8765432): 654
middleThreeDigits(-9223372036854775808): 368
middleThreeDigits(9223372036854775807): 368

middleThreeDigits(1): n is too short.
middleThreeDigits(2): n is too short.
middleThreeDigits(-1): n is too short.
middleThreeDigits(-10): n is too short.
middleThreeDigits(2002): n must have an odd number of digits.
middleThreeDigits(-2002): n must have an odd number of digits.
middleThreeDigits(0): n is too short.
middleThreeDigits(15): n is too short.

middleThreeDigits(cast(short)-32768): 276

J

Solution: <lang j>asString=: ":"0 NB. convert vals to strings getPfxSize=: [: -: 3 -~ # NB. get size of prefix to drop before the 3 middle digits getMid3=: (3 {. 'err' ,~ getPfxSize }. ]) :: ('err'"_) NB. get 3 middle digits or return 'err' getMiddle3=: getMid3@asString@:|</lang> Example: <lang j> vals=: 123 12345 1234567 987654321 10001 _10001 _123 _100 100 _12345 1 2 _1 _10 2002 _2002 0

  getMiddle3 vals

123 234 345 654 000 000 123 100 100 234 err err err err err err err</lang>

OCaml

<lang ocaml>let even x = (x land 1) <> 1

let middle_three_digits x =

 let s = string_of_int (abs x) in
 let n = String.length s in
 if n < 3 then failwith "need >= 3 digits" else
 if even n then failwith "need odd number of digits" else
 String.sub s (n / 2 - 1) 3

let passing = [123; 12345; 1234567; 987654321; 10001; -10001; -123; -100; 100; -12345] let failing = [1; 2; -1; -10; 2002; -2002; 0]

let print x =

 let res =
   try (middle_three_digits x)
   with Failure e -> "failure: " ^ e
 in
 Printf.printf "%d: %s\n" x res

let () =

 print_endline "Should pass:";
 List.iter print passing;
 print_endline "Should fail:";
 List.iter print failing;
</lang>
Output:
Should pass:
123: 123
12345: 234
1234567: 345
987654321: 654
10001: 000
-10001: 000
-123: 123
-100: 100
100: 100
-12345: 234

Should fail:
1: failure: need >= 3 digits
2: failure: need >= 3 digits
-1: failure: need >= 3 digits
-10: failure: need >= 3 digits
2002: failure: need odd number of digits
-2002: failure: need odd number of digits
0: failure: need >= 3 digits

Perl 6

<lang Perl6>sub middle-three($n) {

   given $n.abs {
       when .chars < 3  { "$n is too short" }
       when .chars %% 2 { "$n has an even number of digits" }
       default          { "The three middle digits of $n are: ", .substr: (.chars - 3)/2, 3 }
   }

}

say middle-three($_) for <

   123 12345 1234567 987654321 10001 -10001 -123 -100 100 -12345
   1 2 -1 -10 2002 -2002 0

>;</lang>

Output:
The three middle digits of 123 are:  123
The three middle digits of 12345 are:  234
The three middle digits of 1234567 are:  345
The three middle digits of 987654321 are:  654
The three middle digits of 10001 are:  000
The three middle digits of -10001 are:  000
The three middle digits of -123 are:  123
The three middle digits of -100 are:  100
The three middle digits of 100 are:  100
The three middle digits of -12345 are:  234
1 is too short
2 is too short
-1 is too short
-10 is too short
2002 has an even number of digits
-2002 has an even number of digits
0 is too short

Python

<lang python>>>> def middle_three_digits(i): s = str(abs(i)) length = len(s) assert length >= 3 and length % 2 == 1, "Need odd and >= 3 digits" mid = length // 2 return s[mid-1:mid+2]

>>> passing = [123, 12345, 1234567, 987654321, 10001, -10001, -123, -100, 100, -12345] >>> failing = [1, 2, -1, -10, 2002, -2002, 0] >>> for x in passing + failing: try: answer = middle_three_digits(x) except AssertionError as error: answer = error print("middle_three_digits(%s) returned: %r" % (x, answer))


middle_three_digits(123) returned: '123' middle_three_digits(12345) returned: '234' middle_three_digits(1234567) returned: '345' middle_three_digits(987654321) returned: '654' middle_three_digits(10001) returned: '000' middle_three_digits(-10001) returned: '000' middle_three_digits(-123) returned: '123' middle_three_digits(-100) returned: '100' middle_three_digits(100) returned: '100' middle_three_digits(-12345) returned: '234' middle_three_digits(1) returned: AssertionError('Need odd and >= 3 digits',) middle_three_digits(2) returned: AssertionError('Need odd and >= 3 digits',) middle_three_digits(-1) returned: AssertionError('Need odd and >= 3 digits',) middle_three_digits(-10) returned: AssertionError('Need odd and >= 3 digits',) middle_three_digits(2002) returned: AssertionError('Need odd and >= 3 digits',) middle_three_digits(-2002) returned: AssertionError('Need odd and >= 3 digits',) middle_three_digits(0) returned: AssertionError('Need odd and >= 3 digits',) >>> </lang>

REXX

<lang rexx>/* REXX ***************************************************************

  • 03.02.2013 Walter Pachl
                                                                                                                                            • /

sl='123 12345 1234567 987654321 10001 -10001 -123 -100 100 -12345',

  '2 -1 -10 2002 -2002 0 abc 1e3 -17e-3'

Do While sl<> /* loop through test values */

 Parse Var sl s sl                    /* pick next value            */
 Call mid3 s                          /* test it                    */
 End

Exit mid3: Procedure Parse arg d /* take the argument */ Select /* first test for valid input */

 When datatype(d)<>'NUM'   Then Call error 'not a number'
 When pos('E',translate(d))>0 Then Call error 'not just digits'
 When length(abs(d))<3     Then Call error 'less than 3 digits'
 When length(abs(d))//2<>1 Then Call error 'not an odd number of digits'
 Otherwise Do                         /* input is ok                */
   dx=abs(d)                          /* get rid of optional sign   */
   ld=length(dx)                      /* length of digit string     */
   z=(ld-3)/2                         /* number of digits to cut    */
   Say left(d,12) '->' substr(dx,z+1,3) /* show middle 3 digits     */
   End
 End
 Return

error:

 Say left(d,12) '->' arg(1)           /* tell about the problem     */
 Return

</lang> Output:

123          -> 123
12345        -> 234
1234567      -> 345
987654321    -> 654
10001        -> 000
-10001       -> 000
-123         -> 123
-100         -> 100
100          -> 100
-12345       -> 234
2            -> less than 3 digits
-1           -> less than 3 digits
-10          -> less than 3 digits
2002         -> not an odd number of digits
-2002        -> not an odd number of digits
0            -> less than 3 digits
abc          -> not a number
1e3          -> not just digits
-17e-3       -> not just digits

Rust

<lang rust>fn middle_three_digits(x: int) -> Result<~str, ~str> {

   let s = int::abs(x).to_str();
   let len = s.len();
   if len < 3 {
       Err(~"Too short")
   } else if len % 2 == 0 {
       Err(~"Even number of digits")
   } else {
       Ok(s.slice(len/2 - 1, len/2 + 2))
   }

}

fn print_result(x: int) {

   io::print(fmt!("middle_three_digits(%?) returned: ", x));
   match middle_three_digits(x) {
       Ok(move s) => io::println(fmt!("Success, %s", s)),
       Err(move s) => io::println(fmt!("Failure, %s", s))
   }

}

fn main() {

   let passing = [123, 12345, 1234567, 987654321, 10001, -10001, -123, -100, 100, -12345];
   let failing = [1, 2, -1, -10, 2002, -2002, 0];
   for passing.each |i| {
       print_result(*i);
   }
   for failing.each |i| {
       print_result(*i);
   }

}</lang>

Output:

middle_three_digits(123) returned: Success, 123
middle_three_digits(12345) returned: Success, 234
middle_three_digits(1234567) returned: Success, 345
middle_three_digits(987654321) returned: Success, 654
middle_three_digits(10001) returned: Success, 000
middle_three_digits(-10001) returned: Success, 000
middle_three_digits(-123) returned: Success, 123
middle_three_digits(-100) returned: Success, 100
middle_three_digits(100) returned: Success, 100
middle_three_digits(-12345) returned: Success, 234
middle_three_digits(1) returned: Failure, Too short
middle_three_digits(2) returned: Failure, Too short
middle_three_digits(-1) returned: Failure, Too short
middle_three_digits(-10) returned: Failure, Too short
middle_three_digits(2002) returned: Failure, Even number of digits
middle_three_digits(-2002) returned: Failure, Even number of digits
middle_three_digits(0) returned: Failure, Too short

Vedit macro language

<lang vedit>do {

   #1 = Get_Num("Enter a number, or 0 to stop: ", STATLINE)
   Ins_Text("Input: ") Num_Ins(#1, COUNT, 10)
   Call("MIDDLE_3_DIGITS")
   Ins_Text("  Result: ") Reg_Ins(10) Ins_Newline
   Update()

} while (#1); Return

// Find middle 3 digits of a number // in: #1 = numeric value // out: @10 = the result, or error text //

MIDDLE_3_DIGITS:

Buf_Switch(Buf_Free) Num_Ins(abs(#1), LEFT+NOCR) // the input value as string

  1. 2 = Cur_Col-1 // #2 = number of digits

if (#2 < 3) {

   Reg_Set(10, "Too few digits!")

} else {

   if ((#2 & 1) == 0) {

Reg_Set(10, "Not odd number of digits!")

   } else {

Goto_Pos((#2-3)/2) Reg_Copy_Block(10, Cur_Pos, Cur_Pos+3)

   }

} Buf_Quit(OK) Return </lang>

Output:

Input:        123  Result: 123
Input:      12345  Result: 234
Input:    1234567  Result: 345
Input:  987654321  Result: 654
Input:      10001  Result: 000
Input:     -10001  Result: 000
Input:       -123  Result: 123
Input:       -100  Result: 100
Input:        100  Result: 100
Input:     -12345  Result: 234
Input:          1  Result: Too few digits!
Input:          2  Result: Too few digits!
Input:         -1  Result: Too few digits!
Input:        -10  Result: Too few digits!
Input:       2002  Result: Not odd number of digits!
Input:      -2002  Result: Not odd number of digits!
Input:          0  Result: Too few digits! 

XPL0

<lang XPL0>include c:\cxpl\stdlib;

func Mid3Digits(I); \Return the middle three digits of I int I; int Len, Mid; char S(10); [ItoA(abs(I), S); Len:= StrLen(S); if Len<3 or (Len&1)=0 then return "Must be 3, 5, 7 or 9 digits"; Mid:= Len/2; S:= S + Mid - 1; S(2):= S(2) ! $80; \terminate string return S; \WARNING: very temporary ];

int Passing, Failing, X; [Passing:= [123, 12345, 1234567, 987654321, 10001, -10001, -123, -100, 100, -12345];

Failing:= [1, 2, -1, -10, 2002, -2002, 0];     \WARNING: nasty trick

for X:= 0 to 16 do

   [Text(0, "Middle three digits of ");  IntOut(0, Passing(X));
    Text(0, " returned: ");
    Text(0, Mid3Digits(Passing(X)));  CrLf(0);
   ];

]</lang>

Output:
Middle three digits of 123 returned: 123
Middle three digits of 12345 returned: 234
Middle three digits of 1234567 returned: 345
Middle three digits of 987654321 returned: 654
Middle three digits of 10001 returned: 000
Middle three digits of -10001 returned: 000
Middle three digits of -123 returned: 123
Middle three digits of -100 returned: 100
Middle three digits of 100 returned: 100
Middle three digits of -12345 returned: 234
Middle three digits of 1 returned: Must be 3, 5, 7 or 9 digits
Middle three digits of 2 returned: Must be 3, 5, 7 or 9 digits
Middle three digits of -1 returned: Must be 3, 5, 7 or 9 digits
Middle three digits of -10 returned: Must be 3, 5, 7 or 9 digits
Middle three digits of 2002 returned: Must be 3, 5, 7 or 9 digits
Middle three digits of -2002 returned: Must be 3, 5, 7 or 9 digits
Middle three digits of 0 returned: Must be 3, 5, 7 or 9 digits