44

Is there an inexpensive way to concatenate integers in csharp?

Example: 1039 & 7056 = 10397056

7
  • 7
    Just a note - many of these (string parsing) solutions can have an OverflowException if the combined string is greater than the max integer value (or lower than the min). Commented Jun 18, 2009 at 18:28
  • 1
    Because you didn't give any motiviation WHY you would WANT to concatenate numbers? Commented Jun 18, 2009 at 19:38
  • 2
    What is the concatenation of -1039 and 7056? 1039 and -7056? -1039 and -7056? Concatenation doesn't really make a lot of sense for integers. Commented Jun 18, 2009 at 21:21
  • I would never have negative numbers. These integers represent id's which are incremented and will never be negative. Commented Jun 19, 2009 at 14:56
  • 1
    Then I hope you're using uints. The question led to some good answers, but using ints (or even uints) as an id is a bit of a code smell. Are all the ID's the same number of digits? If not you risk colliding on things like 1 & 11, 11 and 1 vs 111. Commented Jun 19, 2009 at 16:00

13 Answers 13

76

If you can find a situation where this is expensive enough to cause any concern, I'll be very impressed:

int a = 1039;
int b = 7056;

int newNumber = int.Parse(a.ToString() + b.ToString())

Or, if you want it to be a little more ".NET-ish":

int newNumber = Convert.ToInt32(string.Format("{0}{1}", a, b));

int.Parse is not an expensive operation. Spend your time worrying about network I/O and O^N regexes.

Other notes: the overhead of instantiating StringBuilder means there's no point if you're only doing a few concatenations. And very importantly - if you are planning to turn this back into an integer, keep in mind it's limited to ~2,000,000,000. Concatenating numbers gets very large very quickly, and possibly well beyond the capacity of a 32-bit int. (signed of course).

Sign up to request clarification or add additional context in comments.

5 Comments

You only need to call .ToString() on one of the integers.
I agree. This should do the trick. If performance is really important in that part of your code I'd try to profile different solutions to this problem.
@Brandon technically true, but the compiler does the same string conversion either way, so it's only saving a few keystrokes at best.
+1: it often surprises me how many people look for micro-optimizations on code like this instead of doing what just works.
Better if you use string interpolation. ex: Convert.ToInt32($"{a}{b}");
22

I'm a bit late at the party, but recently I had to concatenate integers. With 0 < a,b < 10^9 it can be done quite fast.

static ulong concat(uint a, uint b)
{
    if (b < 10U) return 10UL * a + b;
    if (b < 100U) return 100UL * a + b;
    if (b < 1000U) return 1000UL * a + b;
    if (b < 10000U) return 10000UL * a + b;
    if (b < 100000U) return 100000UL * a + b;
    if (b < 1000000U) return 1000000UL * a + b;
    if (b < 10000000U) return 10000000UL * a + b;
    if (b < 100000000U) return 100000000UL * a + b;
    return 1000000000UL * a + b;
}

Edit: the version below might be interesting (platform target: x64).

static ulong concat(ulong a, uint b)
{
    const uint c0 = 10, c1 = 100, c2 = 1000, c3 = 10000, c4 = 100000,
        c5 = 1000000, c6 = 10000000, c7 = 100000000, c8 = 1000000000;
    a *= b < c0 ? c0 : b < c1 ? c1 : b < c2 ? c2 : b < c3 ? c3 :
         b < c4 ? c4 : b < c5 ? c5 : b < c6 ? c6 : b < c7 ? c7 : c8;
    return a + b;
}

1 Comment

This should be the answer (op asked for an inexpensive way), I've benchmarked some of the answers here and this one came out on top with 36ms (vs 546ms of the accepted answer, and 718ms for the .NET-ish way). I've tested them by generating a million random integers up to 20000 (no overflows) and concatenated every one with the previous one.
12

I don't think you can get any simpler than this:

static uint Concat (uint a, uint b)
{
  uint
    pow = 1;

  while (pow < b)
  {
    pow = ((pow << 2) + pow) << 1;
    a = ((a << 2) + a) << 1;
  }

  return a + b;
}

which has no memory allocations, string conversions or multiplies; or maybe:

static uint Concat (uint a, uint b)
{
  uint
    pow = 1;

  while (pow < b)
  {
    pow = ((pow << 2) + pow) << 1;
  }

  return a * pow + b;
}

If you want to concatenate two binary numbers:

static uint Concat (uint a, uint b)
{
  uint
    mask = uint.MaxValue;

  while ((mask & b) != 0)
  {
    mask <<= 1;
    a <<= 1;
  }

  return a | b;
}

3 Comments

Can't get any simpler? I could believe this is the fastest approach, and the shifting is clever, but I'm not sure it deserves the label "simple." ;)
Also, for a really tight loop you would want to profile (or at least disassemble) to see if the JIT reduces-in-strength constant multiplies by 10 to the shift pattern you have here. It might be that "pow *= 10" results in very similar results to "pow = ((pow << 2) + pow) << 1" or even that the multiply is faster for some arcane reason.
Using the "*10" version on IA32, the compiler/JIT might use the intructions: lea eax,[eax*4+eax] ; add eax,eax. It's a long shot though.
8

inexpensive? String concatenation or formatted string is probably going to be considerably faster.

Otherwise you can do something like:

Math.Pow(10,Math.Ceiling(Math.Log10(second)))*first+second

provided first and second are integers. This is about the only way you'll do it not involving converting to a string and back, but I am extremely doubtful that it will be faster.

1 Comment

I agree, great catch on the Ceiling, and this is just about the only thing I'd be able to believe to be faster than parsing int values to strings and concatenating them.
8
  1. string ConcatInt(int x,int y){return String.Format("{0}{1}",x,y);}
    
  2. int ConcatInt(int x,int y){
       return (x * Math.Pow(10, y.length)) + y;
    }
    

Edit Note: Fixes some mistypes. There are more type issues left. I'm just giving an outline of the answer

The second method should actually be:

static int ConcatInt2(int x, int y) {
   return (int)(x * Math.Pow(10, y.ToString().Length)) + y;
}

2 Comments

#2 seems like it would be faster than a parsing to strings
Not sure how much faster this second method really is, since you are already parsing one int to string anyway (just to get its length). I think in order for this to be really faster than just concatenating two strings, you should use the "old fashion" approach of determining numbers length.
7

If you want to concatenate many ints to a String

StringBuilder sb = new StringBuilder(1039);
sb.Append(7056);
sb.Append(1234);
sb.Append(1235);
....
sb.Append(9999);
sb.ToString();

Comments

3

If we want integer result then:

int result = int.Parse(input1.ToString() + input2.ToString());

For a string result do this:

string result = input1.ToString() + input2.ToString();

Comments

2

The "Mathy" and "No String" method follows:

    int a = 1039;
    int b = 7056;

    int bLen = (int)Math.Ceiling(Math.Log10(b));
    int ab = (a * ((int)Math.Pow(10, bLen))) + b;

Note that it may still be slow because of the Log10 call.

2 Comments

+1 although I'm not 100% convinced that this is faster in practice than string concatenation
Honestly, I'm not convinced it is either. But it works and it's probably worth a try.
2

how about this?

int c = b;
while(c > 0) {
   a *= 10;
   c /= 10;
}
a += b;

Comments

1
public int ConcatInts(int int1, int int2)
{
    return (int)(int1 * Math.Pow(10, int2.ToString().Length)) + int2;
}

Edit: Guess I wasn't the first with this solution!

Comments

1

I have this solution:

const int left = 1039;
const int right = 7056;

int rightLength = 10;

while (rightLength <= right)
{
    rightLength *= 10;
}

return (left * rightLength) + right;

Essentially it's adding 0's to the end of the first number and then adding the second one to it. Like so:

1039 * 10000 = 10390000
10390000 + 7056 = 10397056

I've also ran some benchmarkings with BenchmarkDotNet. Bellow are the test cases and summary of the results:

    public class Benchmarks
    {
        private const int left = 1039;
        private const int right = 7056;
    
        [Benchmark(Baseline = true)]
        public int Scenario1()
        {
            return int.Parse(left.ToString() + right.ToString());
        }
    
        [Benchmark]
        public int Scenario2()
        {
            return Convert.ToInt32(string.Format("{0}{1}", left, right));
        }
    
        [Benchmark]
        public int Scenario3()
        {
            const int left = 1039;
            const int right = 7056;
    
            int rightLength = 10;
    
            while (rightLength <= right)
            {
                rightLength *= 10;
            }
    
            return (left * rightLength) + right;
        }
    
        /*
         * // * Summary *
         * BenchmarkDotNet=v0.13.1, OS=Windows 10.0.22621
         * 11th Gen Intel Core i7-1165G7 2.80GHz, 1 CPU, 8 logical and 4 physical cores
         * .NET SDK=7.0.401
         *   [Host]     : .NET 6.0.22 (6.0.2223.42425), X64 RyuJIT  [AttachedDebugger]
         *   Job-GHXRTE : .NET 6.0.22 (6.0.2223.42425), X64 RyuJIT
     * 
     * Platform=X64  Runtime=.NET 6.0
     * 
     * |    Method |      Mean |     Error |    StdDev | Ratio | RatioSD |  Gen 0 | Allocated |
     * |---------- |----------:|----------:|----------:|------:|--------:|-------:|----------:|
     * | Scenario1 | 41.319 ns | 0.6891 ns | 0.5754 ns |  1.00 |    0.00 | 0.0166 |     104 B |
     * | Scenario2 | 68.891 ns | 1.2541 ns | 1.2878 ns |  1.66 |    0.03 | 0.0139 |      88 B |
     * | Scenario3 |  1.088 ns | 0.0407 ns | 0.0381 ns |  0.03 |    0.00 |      - |         - |
     * 
     * Run time: 00:01:08 (68.84 sec), executed benchmarks: 3
     * Global total time: 00:01:17 (77.57 sec), executed benchmarks: 3 
     */
}

This is the config, for anyone interested:

public class BenchmarkConfig
{
    /// <summary>
    /// Get a custom configuration
    /// </summary>
    /// <returns></returns>
    public static IConfig Get()
    {
        return ManualConfig.CreateEmpty()
            // Jobs
            .AddJob(Job.Default
                .WithRuntime(CoreRuntime.Core60)
                .WithPlatform(Platform.X64))
            // Configuration of diagnosers and outputs
            .AddDiagnoser(MemoryDiagnoser.Default)
            .AddColumnProvider(DefaultColumnProviders.Instance)
            .AddLogger(ConsoleLogger.Default)
            .AddExporter(CsvExporter.Default)
            .AddExporter(HtmlExporter.Default)
            .AddAnalyser(GetAnalysers().ToArray());
    }

    /// <summary>
    /// Get analyser for the cutom configuration
    /// </summary>
    /// <returns></returns>
    private static IEnumerable<IAnalyser> GetAnalysers()
    {
        yield return EnvironmentAnalyser.Default;
        yield return OutliersAnalyser.Default;
        yield return MinIterationTimeAnalyser.Default;
        yield return MultimodalDistributionAnalyzer.Default;
        yield return RuntimeErrorAnalyser.Default;
        yield return ZeroMeasurementAnalyser.Default;
        yield return BaselineCustomAnalyzer.Default;
    }
}

Comments

1

Not really inexpensive, but:

string con = string.Format("{0}{1}",int1,int2);

or

string con = int1.ToString() + int2.ToString();

If you use this in a loop, I think I would use Option 1, which uses a StringBuilder internally.

Comments

0

// Concatenating two numbers program//

        Console.WriteLine("Enter a number for a");
        int a = int.Parse(Console.ReadLine());

        Console.WriteLine("Enter a number for b");
        int b = int.Parse(Console.ReadLine());

        int Concatenating = Convert.ToInt32(string.Format("{0}{1}", a, b));
        Console.WriteLine(Concatenating);
        Console.ReadKey();

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.