c# Efficient solution: Sequence generator for a pattern

This is an interview question to generate the below pattern of numbers in a sequence, which is: 12.34, 23.45, 45.67, 78.910, 1112.1314, 1617.1819, 2223.2425, 2930.3132, 3738.3940, 4647.4849, 5657.5859, 6768.6970, 7980.8182, 9293.9495, 106107.108109, 121122.123124 We can use starting seed number as 12 and have to generate all the 16 numbers programmatically without using strings. We can use only arrays but no other built-in collection classes or data structures.

public static void GenerateSequence()
{
int j = 1;
ArrayList sequenceList = new ArrayList();

for (int count = 0; count < 16; count++)
{
j = j + count;
int quotent = getValue(j, j + 1);
int reminder = getValue(j + 2, j + 3);
int length = getLength(reminder);
double result = Convert.ToUInt32(quotent) * getLength(reminder) + reminder;
}
Console.WriteLine(sequenceList.ToString());
}

static int getValue(int a, int b)
{
return a * getLength(b) + b;
}

static int getLength(int value)
{
int length = (int)(Math.Log10(value) + 1);
int formattedValue = 10;

for (int i = 1; i < length; i++)
formattedValue = formattedValue * 10;

return formattedValue;
}


I've arrived with above solution but this looks complex and less efficient. Looking for an alternate approach with better time/space complexity.

• 12.34, 23.45, 45.67, 78.910 - how is this even a consistent sequence? Wouldn't this go 12.34, 23.45, 34.56, 45.67? Jun 21, 2020 at 23:49
• @Reinderien the sequence is adding 1 to each digit, then 2, then 3... not adding 1 at each step. Jun 22, 2020 at 0:01
• That seems underspecified. It isn't just adding to each digit - it's substituting each digit with all of the digits of the resulting sum. You should spell this out in the question. Jun 22, 2020 at 0:04
• If it is an interview question then they are interested about your solution (skills) not others. Jun 22, 2020 at 6:54

In the question it says

We can use starting seed number as 12 and have to generate all the 16 numbers programmatically without using strings

Was the seed value part of the requirements for the problem? If so, then one test of a solution would be to feed in another seed, say 13, and see if the output matches the expected results for that seed. The current solution is hard-coded to always produce the same outputs.

Although not an explicit requirement, passing in the count of values to be produced as a parameter would be a nice touch (or feeping creaturism, depending upon one's viewpoint).

Testability:
As written, the only way to test the value generation is to run it and sight check the results. Another approach would be to create a function to return the values and the function could then be unit tested, quickly and reliably (sight checking 16 numbers for possibly small differences is doable. If it was 100 numbers it would become a lot more onerous)

Silly(ish):
If the examiners are being picky on an applicant's ability to understand and follow instructions then using the ArrayList breaks the prohibition

use only arrays but no other built-in collection classes or data structures.

It is a very picky point (but interviewers can be picky at times) and it may also hint that they are looking for something along the lines of

public static IEnumerable<double> GetSequence(int seed, int count)
{
// do count times
//  calc value
yield value;
}


If we are going to use a collection to hold the values, why use an ArrayList. A generic List<double> would be better (Why not to use ArrayList in C#).
If we are to follow the collection prohibition, then using a double[] and setting the values by index rather than adding them would work (though I would still push for a function returning an IEnumerable<double>)

public static void GenerateSequence()
{
int j = 1;
var sequence = new double[16];

for (int count = 0; count < 16; count++)
{
j = j + count;
int quotent = getValue(j, j + 1);
int reminder = getValue(j + 2, j + 3);
int length = getLength(reminder);
double result = Convert.ToUInt32(quotent) * getLength(reminder) + reminder;
sequence[count] = (result / length);
}
Console.WriteLine(string.Join(Environment.NewLine, sequence.Select(v => v.ToString())));
}


Variable name j

Why j? Probably you could use something of these: number, value, current_value, current, pivot. Also, j = j + count is better written as j += count.

getValue

That's a poor name - it concatenates two numbers into one, not "gets value"; moreover, it does so only with consecutive numbers (arguments always differ by 1). Probably

int concatWithNext(int n)
{
return n * getLength(n+1) + n + 1;
}


will do better.

"Magic" number 16

Why 16? That's the most obvious thing that can change. Make it an argument of GenerateSequence function. You can even make 16 the default value for that argument.

GenerateSequence should return a value, not output it

Usually, calculations and input/output should reside in different methods.

getLength(reminder) is calculated twice

You can reuse the result of first calculation

Convert.ToUInt32

Why? You want to raise an exception on an overflow? Better do it in getValue method.

Calculation formula

Probably it is better not to multiply and then divide, but divide at once to avoid overflow:

sequenceList.Add( Convert.ToDouble(quotent) + Convert.ToDouble(reminder)/Convert.ToDouble(length);


getLength

I think it should be Math.Log10 and Math.Pow or division by 10 and multiplication by 10, but not together. Division and multiplication are usually slightly faster, but you still need to benchmark it. And the name... it actually doesn't get the length, so it should be roundToPowerOfTen or something.