Issue with LINQ - c#

I created LINQ implementation of mod10 algorithm.
The source code:
string number = "7992739871";
int mod10sum = number.Reverse()
.Select((c, i) => (c - '0') << ((i + 1) & 1)) // Double every other digit and sum the digits of the products (e.g., 10: 1 + 0 = 1, 14: 1 + 4 = 5)
.Sum(c => c - '0') % 10; // together with the undoubled digits from the original number
string checkDigit = (mod10sum == 0 ? 0 : 10 - mod10sum).ToString("0");
Console.WriteLine(checkDigit);
As per the example, 7992739871 number should have check digit as 3; however, what I am getting is 15.
What I am doing wrong? I am sure the mistake is very small but can't find it.

The problem is with the Select method. In order to sum up all the digits (as described in the algorithm) you would need to return 1 and 0 instead of 10, 1 and 4 instead of 14 (as in your example).
The easiest (but it does not have to be the most optimal) way to do that is to conert number from Select to string (14 -> "14") and then split the string characters using SelectMany.
So your code should look as follows:
int mod10sum = number.Reverse()
.SelectMany((c, i) => ((c - '0') << ((i + 1) & 1)).ToString())
.Sum(c => c - '0') % 10;
checkDigit = (mod10sum == 0 ? 0 : 10 - mod10sum).ToString("0");
Console.WriteLine(checkDigit);
A bit of theory
LINQ SelectMany returns IEnumerable<>. When you return string (which is IEnumerable) then that's why SelectMany "splits" returned string into characters.
Microsoft has very nice page (101 LINQ Samples) with different LINQ samples which should help you out.
EDIT
I would also recommend working on that conversion from int to string. I was working on similar project literally yesterday and in my case that conversion is a bit problematic from performance point of view as we call that method millions of times. If you have to calculate lots of mod10's then it might be not the best solution.

I would change the Sum.
At this point, you don't have a sequence of characters, but the single-or-doubled-as-appropriate value for each original digit.
Thus, you don't need to be subtracting 0, you need to be calculating the digit sum of each of these integers, and (since you know they'll be small) you can do this as simply as
.Sum(i => (i % 10) + (i / 10))
giving
string number = "7992739871";
int mod10sum = number.Reverse()
.Select((c, i) => (c - '0') << ((i + 1) & 1))
.Sum(i => (i % 10) + (i / 10)) % 10;
This should be more effecient than calling ToString() and iterating over the result.

Related

Problem with Convert.ToInt32 and getting error Index and length must refer to a location within the string

We want get crc code from a string.
for example: string is (ff03c1) and crc code is (3d).
The bellow code works correctly until the string is less than 186 characters.
sample string:
20000F38080000D1080020110800190D0000000000000000000000000000000020000F38080000D1080020110800190D000000000000000000000000000000020000F38080000D1080020110800190D000000000000000000000000000
But this string not working (187 characters):
20000F38080000D1080020110800190D0000000000000000000000000000000020000F38080000D1080020110800190D000000000000000000000000000000020000F38080000D1080020110800190D000000000000000000000000000**0**
error:
Index and length must refer to a location within the string.
Parameter name: length
public static string CreateCRCCode(string Value)
{
return Enumerable.Range(0, Value.Length)
.Where(x => x % 2 == 0)
.Select(x => Convert.ToInt32(Value.Substring(x, 2), 16))
.Aggregate((i, i1) => i ^ i1)
.ToString("X");
}
how we can use string more than 186 character?
Root cause
The real problem is not with the 186 or 187 characters, the problem is the odd and even, what I tried to say is, you will get the same error for an input of 200 as well. The reason is that,
Consider that the Value = "200" so, Value.Length = 3 and hence Enumerable.Range(0, Value.Length) will gives you 0,1,2.
After applying .Where(x => x % 2 == 0) the collection became 0,2.
So when applying the substring(Value.Substring(x, 2)) it will search for the substring starts at index 2 and off length 2(in the second iteration) which is not a valid index. That causes the error.
Proposed Fix:
I don't get any reason for applying Where(x => x % 2 == 0) in the given snippet, if it is necessary please cross check the conditions and scenarios.
Change the Enumerable.Range based on the collection length like the following:
Enumerable.Range(0, Value.Length % 2 == 0 ? Value.Length : Value.Length-1)

Find first digit of a number using ONLY integer operations

I can't understand how to solve the problem that the teacher gave me.
Given a number N (0 <= N <= 100), find its first digit.
For example:
input: 100
result: 1
input: 46
result: 4
input: 3
result: 3
It seemed easy at first, but (as the teacher said) it should be done using ONLY integer data types (in other words, using +, -, *, / and % operators). Is it even possible to do it this way?
I just can't realize how to extract the first digit from a variable-length number without using things like log10, conditions, "while" loop or string conversion.
Without any conditionals:
int H= N / 100; // Hundreds digit
int T= (N / 10) % 10; // Tens digit
int U= N % 10; // Units digit
int h= H; // Hundreds flag
int t= (T + 9) / 10 * (1 - h); // Tens flag
int u= (1 - t) * (1 - h); // Units flag
int Answer= u * U + t * T + h * H; // Combination
Edit: Now tested for 0 and 100:
var result = n / 10 * (1 - n / 100) + n / 100 + (109 - n) / 100 * n;
How it works:
n | n / 10 * (1 - n / 100) | n / 100 | (109 - n) / 100 * n
-----------------------------------------------------------------
10 - 99 | 1 - 9 | 0 | 0
-----------------------------------------------------------------
100 | 0 | 1 | 0
-----------------------------------------------------------------
0 - 9 | 0 | 0 | 0 - 9
Use a while loop, and keep dividing the input number by 10, so long as we are starting with a value which is greater than or equal to 10. When the modified input is less than ten, then it means we have stripped off all digits to the right, except for the "first" digit.
int input = 100;
while (input >= 10)
{
input /= 10;
}
Console.WriteLine("First digit is: {0}", input);
Demo
This is a non-generic response, and only works because the domain is limited. The idea is to return all the digits (hundred's, ten's, and one's) smooshed together." Some thoughts on specific ranges of numbers:
100 is easy because the ten's and one's units are both zero. There are no other three digit numbers, which is good, because anything with a non-zero one's or ten's place will cause problems below.
All numbers less than 100 can include the hundred's digit in the response because it will always be zero.
Any multiple of 10 is easy, just include the each hundred's ten's and one's value, because the other digits are zero.
The tricky part is the one's place. There needs to be a way to "cancel out" this value if a larger digit is supposed to be returned. For example, 87, we want the 8 but want to cancel out the 7.
This leads to the idea
(ten - 9)*(ten - 8)*(ten - 7)*(ten - 6)*(ten - 5)*(ten - 4)*(ten - 3)*(ten - 2)*(ten - 1)
What happens is that any time the ten's place is non-zero, the above will evaluate to zero. So we can multiply the one's place by this to zero out the one's place when the ten's place is non-zero. However, there's a problem when the ten's place is zero. In that case, we're off by a factor of 9! (nine factorial = 362880) and the wrong sign. This is why an extra minus sign is included, and divide out by 362880 to get the right answer when ten's place is zero.
public int GetFirstDigit(int n)
{
var hundred = (n % 1000) / 100;
var ten = (n % 100) / 10;
var one = n % 10;
return hundred + ten + one*
(
-(ten - 9)*(ten - 8)*(ten - 7)*(ten - 6)*(ten - 5)*(ten - 4)*(ten - 3)*(ten - 2)*(ten - 1)
) / 362880
;
}
check with
Enumerable.Range(0, 101).ToList().ForEach(x => Console.WriteLine(x + ": " + GetFirstDigit(x)));
I tried to solve the case but without success,
I can only achieve finding the first digit if the N is 1 - 100.
Here is my source code for it. Hope it helps
https://dotnetfiddle.net/6XyOfd
static int Result(int input)
{
return input/100 + (input%100/input)*input/10 + (input%10/input)*input;
}
input/100 will return 1 if and only if input equals 100, else 0
(input%100/input) will return 1 if and only if input < 100, else 0
if input is lower than 10, input/10 will be 0
(input%10/input) will return 1 if and only if input < 10, else 0
Caution
This would break if input == 0, see #quanik's answer to handle 0.
However, it will work for 1-999.
if (N < 10)
Output(N)
else if (N < 100)
Output(N / 10)
else
Output(1)

How to find all subset which is the summation of its elements equals to a constant number?

I need to find all number subset to get a number N by summing its elements. I don't know how to get through this type of combination problem. In this combination, order matters for different numbers.
example for the number N=4
1 + 1 + 1 + 1
2 + 1 + 1
1 + 2 + 1
1 + 1 + 2
2 + 2
3 + 1
1 + 3
Zeros are not important for me. So how can I get such number sets as an array for an exact number?
What you're looking for are called integer compositions, or ordered partitions.
Compositions can be generated recursively (in lexicographic order, if I'm not mistaken) as follows:
public static IEnumerable<List<int>> Compositions(int n)
{
if (n < 0)
throw new ArgumentOutOfRangeException(nameof(n));
return GenerateCompositions(n, new List<int>());
}
private static IEnumerable<List<int>> GenerateCompositions(int n, List<int> comp)
{
if (n == 0)
{
yield return new List<int>(comp); // important: must make a copy here
}
else
{
for (int k = 1; k <= n; k++)
{
comp.Add(k);
foreach (var c in GenerateCompositions(n - k, comp))
yield return c;
comp.RemoveAt(comp.Count - 1);
}
}
}
Not tested! This was transcribed from a Python implementation. If anyone would like to make corrections or update the code with more idiomatic C#, feel free.
Also, as #aah noted, the number of compositions of n is 2^(n-1), so this becomes unwieldy even for modest n.
If order doesn't matter, there are simply 2^(N-1) possibilities. (Your example doesn't have 2 + 2 or 4)
You can then represent any sequence by its binary representation. To generate, imagine N 1's in a row, so there are N-1 "spaces" between them. Choosing any subset of spaces, you merge any 1's that are adjacent via a chosen space. You can verify this is 1-1 to all possible sets by expanding any such sequence and inserting these spaces.

Fast algorithm for pandigital check

I'm working on a project for which I need a very fast algorithm for checking whether a supplied number is pandigital. Though the logic seems sound, I'm not particularly happy with performance of the methods described below.
I can check up to one million 9-digit numbers in about 520ms, 600ms and 1600ms respectively. I'm working on a low-latency application and in production I'll have a dataset of about 9 or 9.5 billion 7- to 9-digit numbers that I'll need to check.
I have three candidiates right now (well, really two) that use the following logic:
Method 1: I take an input N, split into into a byte array of its constituent digits, sort it using an Array.Sort function and iterate over the array using a for loop checking for element vs counter consistency:
byte[] Digits = SplitDigits(N);
int len = NumberLength(N);
Array.Sort(Digits);
for (int i = 0; i <= len - 1; i++)
{
if (i + 1 != Digits[i])
return false;
}
Method 2: This method is based on a bit of dubious logic, but I split the input N into a byte array of constituent digits and then make the following test:
if (N * (N + 1) * 0.5 == DigitSum(N) && Factorial(len) == DigitProduct(N))
return true;
Method 3: I dislike this method, so not a real candidate but I cast the int to a string and then use String.Contains to determine if the required string is pandigital.
The second and third method have fairly stable runtimes, though the first method bounces around a lot - it can go as high as 620ms at times.
So ideally I really like to reduce the runtime for the million 9-digit mark to under 10ms. Any thoughts?
I'm running this on a Pentium 6100 laptop at 2GHz.
PS - is the mathematical logic of the second method sound?
Method 1
Pre-compute a sorted list of the 362880 9-digit pandigital numbers. This will take only a few milliseconds. Then for each request, first check if the number is divisible by 9: It must be to be pandigital. If it is, then use a binary search to check if it is in your pre-computed list.
Method 2
Again, check if the number is divisible by 9. Then use a bit vector to track the presence of digits. Also use modular multiplication to replace the division by a multiplication.
static bool IsPandigital(int n)
{
if (n != 9 * (int)((0x1c71c71dL * n) >> 32))
return false;
int flags = 0;
while (n > 0) {
int q = (int)((0x1999999aL * n) >> 32);
flags |= 1 << (n - q * 10);
n = q;
}
return flags == 0x3fe;
}
Method 1 comes in at 15ms/1M. Method 2 comes in at 5.5ms/1M on my machine. This is C# compiled to x64 on an i7 950.
just a thought: (after the definitition of pandigital from wikipedia)
int n = 1234567890;
int Flags = 0;
int Base = 10;
while(n != 0)
{
Flags |= 1<<(n % Base); n /= Base;
}
bool bPanDigital = Flags == ((1 << Base) - 1);

Append a digit to an integer and make sure sum of each digits ends with 1

What is the algorithm in c# to do this?
Example 1:
Given n = 972, function will then append 3 to make 9723, because 9 + 7 + 2 + 3 = 21 (ends with 1). Function should return 3.
Example 2:
Given n = 33, function will then append 5 to make 335, because 3 + 3 + 5 = 11 (ends with 1). Function should return 5.
Algorithms are language independent. Asking for "an algorithm in C#" doesn't make much sense.
Asking for the algorithm (as though there is only one) is similarly misguided.
So, let's do this step by step.
First, we note that only the last digit of the result is meaningful. So, we'll sum up our existing digits, and then ignore all but the last one. A good way to do this is to take the sum modulo 10.
So, we have the sum of the existing digits, and we want to add another digit to that, so that the sum of the two ends in 1.
For the vast majority of cases, that will mean sum + newDigit = 11. Rearranging gives newDigit = 11 - sum
We can then take this modulo 10 (again) in order to reduce it to a single digit.
Finally, we multiply the original number by 10, and add our new digit to it.
The algorithm in general:
(10 - (sum of digits mod 10) + 1) mod 10
The answer of the above expression is your needed digit.
sum of digits mod 10 gives you the current remainder, when you subtract this from 10 you get the needed value for a remainder of 0. When you add 1 you get the needed value to get a remainder of 1. The last mod 10 gives you the answer as a 1 digit number.
So in C# something like this:
static int getNewValue(string s)
{
int sum = 0;
foreach (char c in s)
{
sum += Convert.ToInt32(c.ToString());
}
int newDigit = (10 - (sum % 10) + 1) % 10;
return newDigit;
}
Another alternative using mod once only
int sum = 0;
foreach (char c in s)
sum += Convert.ToInt32(c.ToString());
int diff = 0;
while (sum % 10 != 1)
{
sum++;
diff++;
}
if (diff > 0)
s += diff.ToString();
Well, it's easier in C++.
std::string s = boost::lexical_cast<string>( i );
i = i * 10 + 9 - std::accumulate( s.begin(), s.end(), 8 - '0' * s.size() ) % 10;
Addicted to code golf…

Categories