I am finding it hard to understand the logic of the following algorithm that outputs 8,8. I would appreciate if you could provide some insight.
using System;
namespace Console_Example
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine(g(4) + g(5) + "," + g(6));
Console.ReadKey();
}
static int g(int k)
{
if ((k == 1) || (k == 2))
return 1;
else
return g(k - 1) + g(k - 2);
}
}
}
Just a recursive function. You have to follow all steps.
if k = 1:
return 1;
if k = 2:
return 1;
if k = 3:
return (g(2) + g(1)) result is: 1 + 1 = 2
if k = 4:
return (g(3) + g(2)) result is: (1 + 1) + 1 = 3
if k = 5:
return (g(4) + g(3)) result is: 5 + 3 = 5
if k = 6:
return (g(5) + g(4)) result is: 5 + 3 = 8
This looks very similar to the Fibonacci sequence (wikipedia), where each number is the sum of the two previous numbers.
Because it is a recursive function, look at the return g(k - 1) + g(k - 2); where it calls itself, you must follow all the recursion until it ends.
g(1): 1 -- Because the return 1;
g(2): 1 -- Because the return 1;
g(3): g(2) + g(1) = 1 + 1 = 2 -- Here starts the recursion
g(4): g(3) + g(2) = 2 + 1 = 3
g(5): g(4) + g(3) = 3 + 2 = 5
g(6): g(5) + g(4) = 5 + 3 = 8
So g(4) + g(5) +"," +g(6) would be:
3 + 5 , 8 = 8, 8
Pretty much the sum of the F4 F5 resulting in the F6 value.
A better implementation of the Fibonacci sequence would be
static int Fibonacci(int k)
{
if(k < 0)
throw new ArgumentException("Fibonnaci works with numbers >= 0");
if (k == 0 || k == 1)
return k;
else
return Fibonacci(k - 1) + Fibonacci(k - 2);
}
Related
I'm trying to generate a random number in the range specified and then decide if its valid or not based on some simple arithmetic.
The sum (right after the DEBUG comment) is supposed to be, for example
222 222 222
121 212 121
(the 121 212 121 coefficients are added to each digit. if the product of the numbers is more than 9, then the sum of the digits of the product is recorded otherwise just the product is recorded (21 or 22 in this situation.)
using 222 222 222 as an example number the sum would be...
21 + 22 + 21 + 22 + 21 + 22 + 21 + 22 + 2*1 = 26 in this situation.
The above operations are supposed to be made to the random number generated above, from the specified range. The problem is that this sum is incorrect, when checking it by hand. Please help...
private void button1_Click(object sender, EventArgs e)
{
bool sinvalid = false;
Random randomsin = new Random();
//do until a valid sin is found
do
{
int rsin = randomsin.Next(100000000, 799999999); //get a new random sin
if (Validate(rsin.ToString()) == true) //if validate returns true
{
textBox1.Text = rsin.ToString(); //put the valid sin in the textbox
sinvalid = true; //set current sin to valid
}
} while (sinvalid == false);
}
bool Validate(String sin)
{
int sum = Cdig(sin[0], 1) + Cdig(sin[1], 2) + Cdig(sin[2], 1) + Cdig(sin[3], 2) + Cdig(sin[4], 1) + Cdig(sin[5], 2) + Cdig(sin[6], 1) + Cdig(sin[7], 2) + Cdig(sin[8], 1);
//DEBUG: show this sum, which is always calculated WRONG!~ WHY
label1.Text = sum.ToString();
if (sum % 10 == 0) //if sum is divisible by 10
{
return true;
}
else
{
return false;
}
}
int Cdig(int dig, int n )
{
int dm = dig * n;
if (dm > 9)
{
return 1 + (dm % 10);
}
else
{
return dm;
}
}
i had to convert the chars from sin[0], sin[1] ..etc. to integers.
int sum = Cdig(sin[0]-'0', 1) + Cdig(sin[1]-'0', 2) + Cdig(sin[2]-'0', 1) + Cdig(sin[3]-'0', 2) + Cdig(sin[4]-'0', 1) + Cdig(sin[5]-'0', 2) + Cdig(sin[6]-'0', 1) + Cdig(sin[7]-'0', 2) + Cdig(sin[8]-'0', 1);
strange but it works
Because you're summing char not int
You can use Char.GetNumericValue or you can getbytes from string and use unsafe code
var sum = 0;
var n = 1;
for (int i = 0; i < sin.Length; i++)
{
//int sum = Cdig
var dig = (int) Char.GetNumericValue(sin[i]);
sum += Cdig(dig, n);
if (n == 1)
n = 2;
if (n == 2)
n = 1;
}
The output of this code is
0 1 2 3
But I am not getting the factorial part. I mean 1!=1 (i.e. i factorial equals to 1), so it does not satisfy the condition, so type for input 2 and 3, but they get printed as output?
static void Main(string[] args)
{
int i = 0;
int b = 8, a = 32;
for (i = 0; i <= 10; i++)
{
if ((a / b * 2)== 2)
{
Console.WriteLine( i + " ");
continue;
}
else if (i!=4)
Console.Write(i + " ");
else
break;
}
Console.ReadLine();
}
OK, let's see:
int b = 8, a = 32;
...
a / b * 2 == 32 / 8 * 2 == 4 * 2 == 8
That's why if ((a / b * 2) == 2) will never succeed, and so we can drop this if and simplify the loop into
for (i = 0; i <= 10; i++)
if (i != 4) // i != means "i doesn't equal", not "i factorial equals"
Console.Write(i + " "); // print 0, 1, 2, 3
else
break; // break on 4
Here we can clearly see that the routine will be printing out i up to 4 So you have
0 1 2 3
Side note: in order to avoid such errors, format out your code and let the compiler help you:
i!=4 // Bad, it can be read in different ways (not equal or factorial)
i != 4 // i is not equal to 4
i! = 4 // assign 4 to i factorial: compile time error
i! == 4 // i factorial equals to 4: compile time error - C# doesn't have factorials
I have a number. For instance, my number is 19 . Then I want to populate my drop down with range in multiplication of 5. So my dropdownlist will consist of items of:
1-5
6-10
11-15
16-19
I tried modulus and division, however, I can't seems to get the range. Is there a fixed method?
Sample code
List<string> range = new List<string>();
int number = 19;
int numOfOccur = (19/5);
for (int i = 1; i < numOfOccur ; i++)
{
range.Add(i + " - " + (i * 5))
}
Sometime I think that old school code, without fancy linq is a bit more clear
int maximum = 19;
int multiple = 5;
int init = 1;
while (init + multiple <= maximum )
{
string addToDDL = init.ToString() + "-" + (init + multiple - 1).ToString();
Console.WriteLine(addToDDL);
init += multiple;
}
if(init <= maximum)
{
string last = init.ToString() + "-" + maximum.ToString();
Console.WriteLine(last);
}
Linq solution (modern techs allow us to put it consize):
int number = 19;
int div = 5;
List<string> range = Enumerable
.Range(0, number / div + (number % div == 0 ? 0 : 1))
.Select(i => $"{i * div + 1} - {Math.Min((i + 1) * div, number)}")
.ToList();
Test
Console.Write(string.Join(Environment.NewLine, range));
Returns
1 - 5
6 - 10
11 - 15
16 - 19
When using modulo arithmetics, do not forget about remainders: you have an error in int numOfOccur = (19/5); line. It should be
int numOfOccur = 19 / 5 + (19 % 5 == 0 ? 0 : 1);
for the last incomplete 16 - 19 range to be proceeded.
Add this package to your project : https://www.nuget.org/packages/System.Interactive/
Then you can do this:
IEnumerable<IList<int>> buffers2 = Enumerable.Range(1, 19).Buffer(5);
IList<int>[] result2 = buffers2.ToArray();
// { { 1, 2, 3, 4, 5 }, { 6, 7, 8, 9, 10 }, ...
Don't forget to add System.Interactive namespace to your using block.
I am trying to write a program to identify the occurrences of 3 consecutive integers in a given array of N numbers and replace them with the middle value by deleting the other two.
For example Input->55 99 99 100 101 101 34 35 36 5 28 7 50 50 51 52 52 24 13 14 15 5 6 7 37 31 37 38 39 36 40
Output->55 100 35 5 28 7 51 24 14 6 37 31 38 36 40
To achieve this i wrote this method which accepts array as an input and it returns the modified array.
//input
int[] original = new int[] { 1, 3, 4, 5, 5, 6, 8} ;
List<int> lstoriginal = new List<int>(original);
List<int> modified = Test(lstoriginal);
//method
public static List<int> Test(List<int> arrayInput)
{
for (i = 0; i < arrayInput.Count; i++)
{
if (i + 2 < arrayInput.Count)
{
if (arrayInput[i + 2] == arrayInput[i + 1] + 1
&& arrayInput[i + 2] == arrayInput[i] + 2)
{
arrayInput.RemoveAt(i + 2);
arrayInput.RemoveAt(i);
List<int> temp = arrayInput;
Test(temp);
}
}
}
return arrayInput;
}
Follwoing are the execution steps/result which i analyzed-
1-Initially if the test input is 1, 3, 4, 5, 5, 6, 8
2-When i=1 and it finds that 3,4,5 is in sequence it removes 3 and 5 and list becomes 1,4,5,6,8
3-Next time when i=1 then it finds 4,5,6 and it removes 4 and 6 and the new list is 1,5,8
4-i am expecting to exit from loop when i + 2 < arrayInput.Count returns false and trying to retrun the modified array immediately here the return statement gets executed but instead of return the result it again calls the Test(temp); statement few more times and then get exit. Please suggest
You actually don't need recursion at all. You can perform the task significantly faster by just moving i after you're removed your sequence. Here's a function that is much simpler and does the exact same thing. I tested it on tens of thousands of randomly generated unordered sequences.
public static List<int> Test2(List<int> arrayInput)
{
for (int i = 0; i < arrayInput.Count - 2; i++)
{
if (arrayInput[i + 2] == arrayInput[i + 1] + 1
&& arrayInput[i + 2] == arrayInput[i] + 2)
{
arrayInput.RemoveAt(i + 2);
arrayInput.RemoveAt(i);
i = Math.Max(-1, i - 3); // -1 'cause i++ in loop will increment it
}
}
return arrayInput;
}
That said, to answer your specific question, the best way to exit a recursive loop like your original is to change the signature of your recursive function to return a bool indicating whether or not it actually made any changes. When the first one returns with no changes, they all can exist, so your call to Test can be wrapped in if (!Test(...)) { return; }.
Here's the complete test and test data comparing your original to my modified version:
public static void Main()
{
const int COUNT = 10000;
var r = new Random();
int matchCount = 0;
var stopwatch1 = new Stopwatch();
var stopwatch2 = new Stopwatch();
for (int j = 0; j < COUNT; j++)
{
var list = new List<int>(100) {1};
for(int k=1; k<100; k++)
{
switch(r.Next(5))
{
case 0:
case 1:
case 2:
list.Add(list[k - 1] + 1);
break;
case 3:
list.Add(list[k - 1] + r.Next(2));
break;
case 4:
list.Add(list[k - 1] - r.Next(5));
break;
}
}
stopwatch1.Start();
List<int> copy1 = Test1(new List<int>(list));
stopwatch1.Stop();
stopwatch2.Start();
List<int> copy2 = Test2(new List<int>(list));
stopwatch2.Stop();
string list1 = String.Join(",", copy1);
string list2 = String.Join(",", copy2);
if (list1 == list2)
{
if (copy1.Count == list.Count)
{
Console.WriteLine("No change:" + list1);
}
else
{
matchCount++;
}
}
else
{
Console.WriteLine("MISMATCH:");
Console.WriteLine(" Orig : " + String.Join(",", list));
Console.WriteLine(" Test1 : " + list1);
Console.WriteLine(" Test2 : " + list2);
}
}
Console.WriteLine("Matches: " + matchCount);
Console.WriteLine("Elapsed 1: {0:#,##0} ms", stopwatch1.ElapsedMilliseconds);
Console.WriteLine("Elapsed 2: {0:#,##0} ms", stopwatch2.ElapsedMilliseconds);
}
public static List<int> Test1(List<int> arrayInput)
{
for (int i = 0; i < arrayInput.Count; i++)
{
if (i + 2 < arrayInput.Count)
{
if (arrayInput[i + 2] == arrayInput[i + 1] + 1
&& arrayInput[i + 2] == arrayInput[i] + 2)
{
arrayInput.RemoveAt(i + 2);
arrayInput.RemoveAt(i);
List<int> temp = arrayInput;
Test1(temp);
}
}
else
{ // modified part: return the array
return arrayInput;
}
}
return arrayInput;
}
//method
public static List<int> Test2(List<int> arrayInput)
{
for (int i = 0; i < arrayInput.Count - 2; i++)
{
if (arrayInput[i + 2] == arrayInput[i + 1] + 1
&& arrayInput[i + 2] == arrayInput[i] + 2)
{
arrayInput.RemoveAt(i + 2);
arrayInput.RemoveAt(i);
i = Math.Max(-1, i - 3); // -1 'cause i++ in loop will increment it
}
}
return arrayInput;
}
Please define "cannot exit". Do you mean the for keeps looping indefinitely? I don't see that happening from this code.
What it looks like to me:
This function will:
Step through the input, int by int. Checks to see if this int and the next 2 are sequential. Then it removes this one and the one after next, then feeds the result back into this same function. It then ignores any value this may have given us and continues on its merry way.
You have an input of 8,9,10
It starts to step through: i = 0 and all that.
so it finds that 8,9,10 are sequential, it then removes 8 and 9 and feeds that result into this same function.
So we start over again:
You have an input of 9
It starts to step through: i = 0 again.
it steps through and finds that there are not at least 3 values in the list, and returns the original.
We then completely ignore that result and continue the original loop above. Now i = 1, but there's only 1 thing in the arrayInput anymore, so it should end.
From what you're doing, I see no reason to make a recursive call. You're not doing anything with the result and even if you were, it would only help you if you had a collection like 8,9,10,10,11. Then the first call would trim it down to 9,10,11 and the recursive call would trim it down to 10
At the very outset let me express my sincere thanks to Marc Gravel,Dahlbyk and the rest for helping me to apply linq practically.
The following are few questions which I have faced in an interview to solve applying Linq. As I am not familiar with Linq I solved it without using Linq.
I appreciate the answers which helps me to solve them using Linq
Thanks in advance.
Question 1:
The Problem is to find different digits such that,in whatever order they are used to make a three-digit number,that number will not be divisible by:
3,5,7,11,13 or 17.
To ensure that there is no ambuigity,suppose the three digits
are a,b,and c.Then,none of the combination of the numbers:
say abc,acb,bac,bca,cab and cba will divide by 3,5,7,11,13 or 17.
Example :
When I take 248 none of its combination(284,428,482,842,824) will exactly divisible by 3,5,7,11,13 or 17.
public void FindingRareNumbers()
{
for (int i = 1; i <= 9; i++)
{
for (int j = 1; j <= 9; j++)
{
for (int k = 1; k <= 9; k++)
{
//to form the three digit
string digit = i.ToString() + j.ToString() + k.ToString();
//converting to integer
int StrToDigit = Convert.ToInt32(digit);
char[] digitcombination = digit.ToCharArray();
string PossibleCombination = "";
bool testpassed = false;
int dcount = 0;
#region different possible combinations
for (int p = 0; p <= 2; p++)
{
for (int q = 0; q <= 2; q++)
{
for (int r = 0; r <= 2; r++)
{
// The following condition avoid the repeatance
// of digit like 111,111,111
if (p != q && p != r && r != q)
{
PossibleCombination =
digitcombination[p].ToString() +
digitcombination[q].ToString() +
digitcombination[r].ToString();
int num = Convert.ToInt32(PossibleCombination);
if (num % 3 != 0 && num % 5 != 0 && num % 7 != 0
&& num % 11 != 0 && num % 11 != 0
&& num % 13 != 0 && num % 17 != 0)
{
//count is increment for 6 times
// it satisfies the condition
dcount++;
testpassed = true;
}
}
}
}
}
#endregion combination
if (testpassed && dcount==6)
{
Console.WriteLine(StrToDigit);
}
}
}
}
}
(coding is working)
Question 2:
The task is to arrange the element in matrix so that all rows,columns,and diagonals add up to the same total.(Bit problem in coding ,I am trying to solve it).
------------------
1 2 3
-----------------
4 5 6
-----------------
7 8 9
-----------------
example :
The one of solutions is as follows:
-----------
2 9 4
-----------
7 5 3
----------
6 1 8
----------
I agree that Marc's solution to your first problem is a reasonable approach. But I think there's a larger question here, which is "how do I solve problems like this in a LINQ-ish manner?"
Notice how your solution is completely "procedural" and "imperative". Your code specifies a series of steps that you would execute, one after the other, with deep loops. Each step along the way is meaningless unless you understand its place in the larger whole.
There are two ideas I like to use when solving problems with LINQ:
Describe what the program is doing logically, rather than listing a series of commands
Characterize the problem as a query against a data set rather than as a procedure to follow.
So, what's our data set? We wish to filter out some elements from the set of all combinations of three digits.
How do we filter them? Permute the digits and then perform a divisibility check on each permutation.
OK, so now we have a structure for our program:
var query = from c in ThreeDigitCombinations()
where DivisibilityCheckPasses(c)
select c;
foreach(Combination result in query) Console.WriteLine(result);
And now you can continue breaking down each of those further, solving each sub-problem using LINQ in turn.
Same goes for your "magic square" problem; you're looking for a permutation that has a certain property, so write a generator of permutations, write a filter, and execute it.
For the first:
static IEnumerable<int> Permute(int x, int y, int z)
{
yield return x * 100 + y * 10 + z;
yield return x * 100 + z * 10 + y;
yield return y * 100 + x * 10 + z;
yield return y * 100 + z * 10 + x;
yield return z * 100 + x * 10 + y;
yield return z * 100 + y * 10 + x;
}
static void Main()
{
var divs = new[] {3,5,7,11,13,17};
// combinations of 1-9
var combinations =
from x in Enumerable.Range(1, 7)
from y in Enumerable.Range(x + 1, 8 - x)
from z in Enumerable.Range(y + 1, 9 - y)
select new { x, y, z };
// permute
var qry = from comb in combinations
where !Permute(comb.x, comb.y, comb.z).Any(
i => divs.Any(d => i % d == 0))
select comb;
foreach (var answer in qry)
{
Console.WriteLine("{0}, {1}, {2}", answer.x, answer.y, answer.z);
}
}
For the second - not elegant, but it works (returns the 8 permutations of the sample):
static void Main() {
var data = Enumerable.Range(1, 9);
var magicSquares =
// generate 1st row and deduce the target
from a in data let arrA = new[] { a }
from b in data.Except(arrA) let arrB = new[] { a,b }
from c in data.Except(arrB) let arrC = new[] { a,b,c }
let target = a + b + c
// generate 2nd row and filter to target matches
from d in data.Except(arrC) let arrD = new[] { a,b,c,d }
from e in data.Except(arrD) let arrE = new[] { a,b,c,d,e }
from f in data.Except(arrE) let arrF = new[] { a,b,c,d,e,f }
where d + e + f == target
// generate 3rd row and filter to target matches
from g in data.Except(arrF) let arrG = new[] { a,b,c,d,e,f,g }
from h in data.Except(arrG) let arrH = new[] { a,b,c,d,e,f,g,h }
from i in data.Except(arrH)
where g + h + i == target
// filter columns
&& a + d + g == target
&& b + e + h == target
&& c + f + i == target
// filter diagonals
&& a + e + i == target
&& c + e + g == target
select new {a,b,c,d,e,f,g,h,i};
foreach (var row in magicSquares)
{
Console.WriteLine("{0} {1} {2}", row.a, row.b, row.c);
Console.WriteLine("{0} {1} {2}", row.d, row.e, row.f);
Console.WriteLine("{0} {1} {2}", row.g, row.h, row.i);
Console.WriteLine();
}
}