0

I want to ask how I can reorder the digits in an Int32 so they result in the biggest possible number. Here is an example which visualizes what I am trying to do:

2927466  -> 9766422
12492771 -> 97742211

I want to perform the ordering of the digits without using the System.Linq namespace and without converting the integer into a string value. This is what I got so far:

public static int ReorderInt32Digits(int v)
    {
        int n = Math.Abs(v);
        int l = ((int)Math.Log10(n > 0 ? n : 1)) + 1;
        int[] d = new int[l];
        for (int i = 0; i < l; i++)
        {
            d[(l - i) - 1] = n % 10;
            n /= 10;
        }
        if (v < 0)
            d[0] *= -1;
        Array.Sort(d);
        Array.Reverse(d);
        int h = 0;

        for (int i = 0; i < d.Length; i++)
        {
            int index = d.Length - i - 1;
            h += ((int)Math.Pow(10, index)) * d[i];
        }
        return h;
    }

This algorithm works flawlessly but I think it is not very efficient. I would like to know if there is a way to do the same thing more efficiently and how I could improve my algorithm.

yq8
  • 145
  • 1
  • 10
  • 2
    split each character / digit then add to a sorted list. Then concatenate them back to an int. Not sure if it is the fastest way but it will work. Also make sure to check for a value higher than int.max – deathismyfriend May 27 '15 at 00:33

5 Answers5

10

You can use this code:

var digit = 2927466;
String.Join("", digit.ToString().ToCharArray().OrderBy(x => x));

Or

var res = String.Join("", digit.ToString().ToCharArray().OrderByDescending(x => x) );
Peyman
  • 3,068
  • 1
  • 18
  • 32
  • 1
    Thanks for the reply, but as stated above I am looking for a non-Linq solution which is faster than mine. Also, your algorithm is converting the digit into a string which I also like to avoid if possible as mentioned before :) – yq8 May 27 '15 at 00:43
  • 2
    Welcome @yq8, sorry I didn't see that. Is there any reason that you don't want use Linq? – Peyman May 27 '15 at 00:44
  • Your result also returns the int in the lowest order not highest. – deathismyfriend May 27 '15 at 01:01
3

Not that my answer may or may not be more "efficient", but when I read your code you calculated how many digits there are in your number so you can determine how large to make your array, and then you calculated how to turn your array back into a sorted integer.

It would seem to me that you would want to write your own code that did the sorting part without using built in functionality, which is what my sample does. Plus, I've added the ability to sort in ascending or descending order, which is easy to add in your code too.

UPDATED

The original algorithm sorted the digits, now it sorts the digits so that the end result is the largest or smallest depending on the second parameter passed in. However, when dealing with a negative number the second parameter is treated as opposite.

using System;

public class Program
{
    public static void Main()
    {
        int number1 = 2927466;
        int number2 = 12492771;
        int number3 = -39284925;

        Console.WriteLine(OrderDigits(number1, false));
        Console.WriteLine(OrderDigits(number2, true));
        Console.WriteLine(OrderDigits(number3, false));
    }

    private static int OrderDigits(int number, bool asc)
    {   
        // Extract each digit into an array
        int[] digits = new int[(int)Math.Floor(Math.Log10(Math.Abs(number)) + 1)];
        for (int i = 0; i < digits.Length; i++)
        {
            digits[i] = number % 10;
            number /= 10;
        }

        // Order the digits
        for (int i = 0; i < digits.Length; i++)
        {
            for (int j = i + 1; j < digits.Length; j++)
            {               
                if ((!asc && digits[j] > digits[i]) ||
                    (asc && digits[j] < digits[i]))
                {
                    int temp = digits[i];
                    digits[i] = digits[j];
                    digits[j] = temp;
                }
            }
        }

        // Turn the array of digits back into an integer
        int result = 0;     
        for (int i = digits.Length - 1; i >= 0; i--)
        {
            result += digits[i] * (int)Math.Pow(10, digits.Length - 1 - i);
        }

        return result;
    }
}

Results:

9766422
11224779
-22345899

See working example here... https://dotnetfiddle.net/RWA4XV

Shar1er80
  • 9,001
  • 2
  • 20
  • 29
  • +1 +Answered for this reply! Extremely nice algorithm, very good work! :) This is much better than mine! – yq8 May 27 '15 at 02:29
  • 1
    @yq8 note that you should also try bucket sort - instead of sorting digits count them, at the end you have array of number of each digit 0-9 in corresponding elements of `int counter[10]` without any sorting. – Alexei Levenkov May 27 '15 at 02:41
  • Shar1er80 - I'm not convinced that `-99854322` is really biggest possible number - `-29985432` is definitely bigger than that... – Alexei Levenkov May 27 '15 at 02:43
  • 1
    @AlexeiLevenkov Took you comment into consideration. My original algorithm only sorted the digits and didn't take into account about producing the largest number as the result. Answer is updated. – Shar1er80 May 27 '15 at 03:00
1
public static int ReorderInt32Digits(int v)
{
    var nums = Math.Abs(v).ToString().ToCharArray();
    Array.Sort(nums);
    bool neg = (v < 0);
    if(!neg)
    {
        Array.Reverse(nums);    
    }
    return int.Parse(new string(nums)) * (neg ? -1 : 1);
}
Aaron Anodide
  • 16,906
  • 15
  • 62
  • 121
1

This code fragment below extracts the digits from variable v. You can modify it to store the digits in an array and sort/reverse.

int v = 2345;

while (v > 0) {
   int digit = v % 10;
   v = v / 10;
   Console.WriteLine(digit);
}

You can use similar logic to reconstruct the number from (sorted) digits: Multiply by 10 and add next digit.

Atul Sikaria
  • 296
  • 1
  • 8
1

I'm posting this second answer because I think I got the most efficient algorithm of all (thanks for the help Atul) :)

void Main()
{
    Console.WriteLine (ReorderInt32Digits2(2927466));
    Console.WriteLine (ReorderInt32Digits2(12492771));      
    Console.WriteLine (ReorderInt32Digits2(-1024));
}

public static int ReorderInt32Digits2(int v)
{
    bool neg = (v < 0);
    int mult = neg ? -1 : 1;
    int result = 0;
    var counts = GetDigitCounts(v);
    for (int i = 0; i < 10; i++)
    {
        int idx = neg ? 9 - i : i;
        for (int j = 0; j < counts[idx]; j++)
        {
            result += idx * mult;
            mult *= 10;         
        }
    }
    return result;
}

// From Atul Sikaria's answer
public static int[] GetDigitCounts(int n)
{
    int v = Math.Abs(n);
    var result = new int[10];
    while (v > 0) {
        int digit = v % 10;
        v = v / 10;
        result[digit]++;
    }
    return result;
}
Aaron Anodide
  • 16,906
  • 15
  • 62
  • 121