views:

379

answers:

3

As stated in problem 37 at Project Euler:

The number 3797 has an interesting property. Being prime itself, it is possible to continuously remove digits from left to right, and remain prime at each stage: 3797, 797, 97, and 7. Similarly we can work from right to left: 3797, 379, 37, and 3.

I already solved this problem (answer ends with 7 :-), but a doubt remains: how efficiently left/right truncate a number, WITHOUT using strings? I built following code, but it seems ugly:

public static void Main()
{
    Console.WriteLine( // 3797, 379, 37, 3, 797, 97, 7
        String.Join(", ", 3797L.Truncate().ToArray()));
    Console.ReadLine();
}

static IEnumerable<long> Truncate(this long number)
{
    yield return number;

    long aux = number;
    while ((aux /= 10) > 0) // right to left
        yield return aux;

    // god forgive me, but it works
    while ((number = (number.Reverse() / 10).Reverse()) > 0) // left to right
    {
        yield return number;
    }
}

public static long Reverse(this long number)
{
    long reverse = number % 10;
    number = number / 10;
    while (number != 0)
    {
        reverse = (number % 10) + (10 * reverse);
        number = number / 10;
    }
    return reverse;
}

EDIT: I ended with this code:

static IEnumerable<long> Truncate(this long number)
{
    yield return number;

    int i = 10;
    while (number / i > 0)
    {
        yield return number / i;
        yield return number % i;
        i *= 10;
    }
}
+10  A: 

To truncate the rightmost digit, divide by 10 (your code already does that).

To truncate one digit on the left of a n-digit number, take the modulo of the number by 10^(n-1).

Example: 3797 % 1000 -> 797

EDIT: to clarify how I suggest to get the value for the modulo:

w <- n
d <- 1
while (w <> 0)
  test primality of w
  w <- w / 10
  d <- d * 10
end
w <- n
while (d <> 10)
  d <- d / 10
  w <- w % d
  test primality of w
end
Pascal Cuoq
how to determine `n` without strings?
Rubens Farias
That's one plus the integral part of the base-10 logarithm of your number. If your language doesn't have log10 but only e-base logarithm, you can convert one into the other by dividing by the e-base logarithm of 10.
Pascal Cuoq
Note that computing a logarithm to determine the number of digits is a little overkill. You could get the number of digits by counting them with successive divisions by 10 and it may be more economical. Especially, you can count the digits at the same time you are removing digits from right to left in the first pass.
Pascal Cuoq
@Pascal, this answer made me cry, ty =)
Rubens Farias
+1  A: 

Could you not divide by tens?

3797/10 = 379

379/10= 37

37/10=3

No strings needed.

To go the other way use %

JonH
+1, that rang a bell, ty
Rubens Farias
+1  A: 
var numbers = GetNumbers(3797);  

public static IEnumerable<int> GetNumbers(int val)
        {
            int ba = 1;
            int result = 1;

            while(result > 0)
            {

                ba *= 10;
                result = val / ba;
                if(result > 0)
                    yield return result;
            }

        }

will produce

379 37 3

Stan R.
+1, this, combined with JonH answer, made my final implementation, ty
Rubens Farias