Recursively checking for a duplicate random number in a database [closed] - c#

It's difficult to tell what is being asked here. This question is ambiguous, vague, incomplete, overly broad, or rhetorical and cannot be reasonably answered in its current form. For help clarifying this question so that it can be reopened, visit the help center.
Closed 9 years ago.
I create a random number and then I check if it exists in a database table. If it does, I generate another one and check again, so would the following work?
public int GenerateNumber()
{
Random r = new Random();
int num = r.Next(1000);
//Psuedo-code
if(num is in table)
GenerateNumber();
return num;
}
It seems based on the answers below that recursion should be avoided here and I should auto-increment the number, so would a good alternative be to either start the auto-increment at 1 and pad with 0's until is is 8 characters long or start at 10,000,000.
Also, what if the datatype has to be a varchar(8). How can I auto-increment a number, but store in it in a varchar(8)?

There are numerous problems with your approach here that have been addressed by others, so instead I'll answer a question you should have asked but didn't:
What are the characteristics that a problem must have in order to correctly use recursion?
You must not use recursion unless your solution exhibits all of the following characteristics:
There is a "trivial" version of the problem that can always be solved without recursion.
Every non-trivial problem can be reduced to one or more strictly smaller problems.
Repeatedly reducing a problem to a smaller problem eventually results in an attempt to solve a trivial problem, after a small number of steps, where by "small" we mean, say, a few hundred steps, not a few million. (This condition can be relaxed in "tail recursive" languages; C# is not a tail recusive language.)
The solutions to the smaller problems can always be efficiently combined into a solution to the larger problem.
Your sample code exhibits none of these characteristics; use of recursion requires that you exhibit all of these characteristics, so under no circumstances should you use recursion.
Let me give you an example of a problem that is well solved by recursion:
A tree is either empty or consists of a left and right sub-tree; the tree never contains loops. The height of an empty tree is zero; the height of a non-empty tree is the length of the longest path from the root to the "deepest" empty sub-tree. Write a method that determines the height of a tree, assuming that the height is less than 200.
This problem exhibits all the characteristics of a problem that can be solved with recursion, so we can do so. Every recursive program has the pattern:
Solve the trivial problem if you can.
Otherwise, split up the problem into smaller problems, solve them recursively, and compose the solutions.
So let's do that:
int Height(Tree tree)
{
// Trivial case:
if (tree.IsEmpty) return 0;
// Non-trivial case: reduce the problem to two smaller problems:
int leftHeight = Height(tree.Left);
int rightHeight = Height(tree.Right);
int height = Math.Max(leftHeight, rightHeight) + 1;
return height;
}

This is not a problem that needs to be solved by recursion. Not to mention the fact that if you have a fair few numbers in your database, and this loops lots of times, you'll quickly get a Stack overflow error. Why not change it to an iterative function:
public int GenerateNumber()
{
Random r = new Randon();
int num = r.Next(1000);
while(num is in database)
{
num = r.Next(1000);
}
return num;
}
A different approach, while I'm here
Why not implement some transitive difference between these values? I.e: The first number is one, then two etc. Then all you need to do is get the most recent entry, and add one to it. No need to consistently keep making database queries.

This could result in a very bad performance. Use, for ex, Guid, for this
var rand = Guid.NewGuid().ToString()

Not quite.
if (num is in table)
return GenerateNumber();
else
return num;
would work, but it's easier/safer to just loop:
int num;
do
{
num = r.Next(1000);
} while (num is in table);
return num;

No it won't. You need to get the number you get from calling GenerateNumber again.
public int GenerateNumber()
{
Random r = new Randon();
int num = r.Next(1000);
//Psuedo-code
if(num is in table)
num = GenerateNumber(); //num = added.
return num;
}
Now you don't need to recursively solve this, and in C# it isn't a good idea, because C# doesn't do tail optimization like other languages (it doesn't change a recursive call to an iterative one for you during compile time). This will work, but your doing extra work on the stack, and you could get a stack overflow error. However, since you asked, this is how you fix the code to work.
You can easily change it to not use recursion by doing:
while(num is in table){ //I always use brackets to be clear.
num = r.Next(1000);
}

Use iteration to avoid crashing with a StackOverFlow exception which will inevitably happen if your table is of sufficient size.
public int GenerateNumber()
{
bool match = false;
while (!match) {
Random r = new Randon();
int num = r.Next(1000);
//Psuedo-code
if(num is not in table)
//insert
}
return num;
}

You don't specify what your database is. If it is just a in memory list of used numbers your code can simply done like this:
private HashSet<int> _usedNumbers = new HashSet<int>();
Random r = new Random(); //Search "Random is not random" on SO to see why I moved this out here.
public int GenerateNumber()
{
int MaxNum = 1000;
int num = r.Next(MaxNum);
if(_usedNumbers.Count == MaxNum)
throw new Exception("I ran out of numbers :(");
while(_usedNumbers.Add(num) == false) //Add will return false if the number already was used.
{
num = r.Next(MaxNum );
}
return num;
}

Related

What is stopping this program from having an output

I made this code to brute force anagrams by printing all possible permutables of the characters in a string, however there is no output. I do not need simplifications as I am a student still learning the basics, I just need help getting it to work this way so I can better understand it.
using System;
using System.Collections.Generic;
namespace anagramSolver
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Enter anagram:");
string anagram = Console.ReadLine();
string temp = "";
List<string> storeStr = new List<string>(0);
List<int> storeInt = new List<int>(0);
//creates factorial number for anagram
int factorial = 1;
for (int i = anagram.Length; i > 0; i--)
{
factorial *= i;
}
while (storeStr.Count != factorial)
{
Random rnd = new Random();
while(temp.Length != anagram.Length)
{
int num = rnd.Next(anagram.Length - 1);
if (storeInt.Contains(num) == true)
{
}
else
{
storeInt.Add(num);
temp += anagram[num];
}
}
if (storeStr.Contains(temp) == true)
{
temp = "";
}
else
{
storeStr.Add(temp);
Console.WriteLine(temp, storeStr.Count);
temp = "";
}
}
}
}
}
edit: added temp reset after it is deemed contained by storeStr
Two main issues causing infinite loop:
1)
As per Random.Next documentation, the parameter is the "exclusive" upper bound. This means, if you want a random number between 0 and anagram.Length - 1 included, you should use rnd.Next(anagram.Length);.
With rnd.Next(anagram.Length - 1), you'll never hit anagram.Length - 1.
2)
Even if you solve 1, only the first main iteration goes well.
storeInt is never reset. Meaning, after the first main iteration, it will have already all the numbers in it.
So, during the second iteration, you will always hit the case if (storeInt.Contains(num) == true), which does nothing and the inner loop will go on forever.
Several issues here...
The expression rnd.Next(anagram.Length - 1) generates a value between 0 and anagram.Length - 2. For an input with two characters it will always return 0, so you'll never actually generate a full string. Remove the - 1 from it and you'll be fine.
Next, you're using a list to keep track of the character indices you've used already, but you never clear the list. You'll get one output (eventually, when the random number generator covers all the values) and then enter an infinite loop on the next generation pass. Clear storeInt after the generation loop to fix this.
While not a true infinite loop, creating a new instance of the random number generator each time will give you a lot of duplication. new Random() uses the current time as a seed value and you could potentially get through a ton of loops with each seed, generating exactly the same values until the time changes enough to change your random sequence. Create the random number generator once before you start your main loop.
And finally, your code doesn't handle repeated input letters. If the input is "aa" then there is only a single distinct output, but your code won't stop until it gets two. If the input was "aab" there are three distinct permutations ("aab", "aba", "baa") which is half of the expected results. You'll never reach your exit condition in this case. You could do it by keeping track of the indices you've used instead of the generated strings, it just makes it a bit more complex.
There are a few ways to generate permutations that are less error-prone. In general you should try to avoid "keep generating random garbage until I find the result I'm looking for" solutions. Think about how you personally would go about writing down the full list of permutations for 3, 4 or 5 inputs. What steps would you take? Think about how that would work in a computer program.
this loop
while(temp.Length != anagram.Length)
{
int num = rnd.Next(anagram.Length - 1);
if (storeInt.Contains(num) == true)
{
}
else
{
storeInt.Add(num);
temp += anagram[num];
}
}
gets stuck.
once the number is in storeInt you never change storeStr, yet thats what you are testing for loop exit

Is there a way to make this recursive function faster? [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 3 years ago.
Improve this question
I am trying to get numbers that sum up 28.(this is just an example, however the target number can be changed). The below piece of code take approximately 4-5 min. Is there a way to make it a little faster to get combinations of numbers that sum up to "28"
output example 0,0,0,0,1,1,1,2,2,3,3,3
private void Button1_Click(object sender, EventArgs e)
{
int up = 28;
int rows = 12;
int[] chosen = new int[rows + 1];
CalculateCombination(chosen, 0, rows, 0, up - 1);
}
public void CalculateCombination(int[] chosen, int index, int r, int start, int end)
{
if (index == r)
{
return;
}
for (int i = start; i <= end; i++)
{
chosen[index] = i;
CalculateCombination(chosen, index + 1, r, i, end);
if (chosen.Sum() + chosen.Length == 28)
{
var ch = string.Join(",", chosen.Take(chosen.Length - 1));
Debug.Write(ch);
Debug.WriteLine("\t");
}
}
return;
}
First off, I assume you are doing this for an assignment. You are required to cite sources that helped you rather than passing off my work as your own in an academic context, so make sure to document in your assignment where you got help from. Don't just copy a solution and claim it as your own.
UPDATE: I misunderstood the problem from the description; I understood the problem to be to find the monotone nondecreasing sequences of length 12 that sum to 28. The problem has been clarified by the original poster in a comment; the problem is to find all non-negative sequences of a given length, say, 12 that sum to a given value, say, 28. There are 1676056044 such sequences, and enumerating them all will take some time. The answer which follows is addressed to the problem as I originally understood it.
Yes, this problem can be solved much more efficiently and clearly than you're doing here. Let's break it down.
First off, every recursive problem has one or more base cases. These are the cases that are so simple that they cannot be reduced to a simpler problem. Let's make an entrypoint and then list the base cases. What do we want? We want all the sequences of a given length, in order from smallest to largest, such that the sequence sums to a particular value.
public static IEnumerable<IEnumerable<int>> SumsTo(int sum, int least, int length)
{
OK, what are the base cases?
If length is zero and sum is zero then the empty sequence is the only solution.
If length is zero and sum is non-zero then there is no solution.
We can easily implement these rules:
if (length == 0)
{
if (sum == 0)
yield return Enumerable.Empty<int>();
yield break;
}
All right, that deals with length being zero. What about length non-zero? Are there any base cases there? Yes. If least * length is greater than sum then there cannot be any solution.
if (least * length > sum)
yield break;
All right. We know that length is at least 1 and that there is definitely a solution. What are the solutions? Well, there has to be a first number in the sequence, and it can be any value between least and sum, so let's write a loop.
for (int current = least; current <= sum; current += 1)
{
What is the solution given current? It is current followed by a sequence of size length-1 where the smallest item is current or larger that sums to sum - current. But we can compute that recursively!
var head = Enumerable.Repeat(current, 1);
foreach(var tail in SumsTo(sum - current, current, length - 1))
yield return head.Concat(tail);
}
}
And we're done:
Console.WriteLine(SumsTo(28, 0, 12).Count());
Prints out 3036, as expected and takes a fraction of a second; there are 3036 ways to sum 12 numbers from 0 to 28 to 28.
EXERCISE: make a type Sum that is either (1) empty, or (2) an integer, called the head, followed by a Sum (either empty or made of only larger elements) called the tail. Rewrite the solution so that it returns IEnumerable<Sum> rather than IEnumerable<IEnumerable<int>>.
EXERCISE: Make your Sum type implement IEnumerable<int> correctly.
EXERCISE: We generate some sums over and over again; for example, of the 3036 solutions to the length is 12, sum is 28 problem, over 100 of them end with "5, 5" so we're allocating that object many times. Memoize your solution so that it returns the same Sum object when given the same arguments.
EXERCISE: Compute the approximate amount of computation you save with this memoized solution; contrast that with the amount of memory you use. Did memory usage go up or down? Did computation speed go up or down? What does this tell you about the efficiency of memoization for this problem? Can you propose a better memoization algorithm?
EXERCISE: I have a particular pattern for strings in mind; we'll call them frob strings. It goes like this: () is a frob string, and (XY) where X and Y are replaced with frob strings is a frob string. So for example (()()) is a frob string, as is (()(()())). Make a method static IEnumerable<string> AllFrob(int s) that gives all frob strings with s pairs of parentheses. So AllFrob(1) is just (). AllFrob(2) is empty; there are no frob strings with two pairs of parentheses. AllFrob(3) is (()()), AllFrob(4) is empty, AllFrob(5) is (()(()())) and ((()())()).

Fibonacci Series recursive c# method

I have hard time writing a method which returns a fibonacci series using recursion.
My iterative method is as follows:
public static string Fibonacci(int n)
{
if (n < 2)
return "1";
int[] numbers = new int[n];
numbers[0]=0;
numbers[1]=1;
for (int i = 2; i < n; i++)
{
numbers[i] = numbers[i - 1] + numbers[i - 2];
}
return string.Join(" ", numbers);
}
I want above method to be changed to recursive call but with same signature ie return type is string and it returns Fibonacci series e.g 0,1,1,2,3,5,8,13,21,34,55
I googled but everywhere I see its done using Console.WriteLine() i.e. values are printed to screen but not returned as string from function.
Thanks
There are, of course, many examples of Fibonacci algorithms on the web, recursive and otherwise. Naturally, the key to a recursive implementation is to take the results from the recursive call, combine that with the current result, and then return that to the caller.
So let's start with the basic Fibonacci idea, with a recursive method that just writes out the numbers as they are generated:
void Fibonacci(int iMinus2, int iMinus1, int count)
{
if (count == 0) return;
int current = iMinus2 + iMinus1;
Console.WriteLine(current);
Fibonacci(iMinus1, current, count - 1);
}
So then the question is, how do we adjust the above so that it returns a string instead of just writing out the numbers one at a time. Again, remember that the key is to always have a way to combine the current result with the combined result of the previous calls. In this case, that means we want to convert the current number to a string, and prepend that string to the string returned by the recursive call (which is all the numbers after the current number:
string Fibonacci(int iMinus2, int iMinus1, int count)
{
if (count == 0) return null;
int current = iMinus2 + iMinus1;
string nextNumbers = Fibonacci(iMinus1, current, count - 1);
return nextNumbers != null ?
current.ToString() + ", " + nextNumbers : current.ToString();
}
Note: the above is a bit more complicated than I'd suggested, because it handles avoiding the addition of a comma when there are no more next numbers. There are other ways to implement this, but I prefer implementing recursive methods such that the terminating condition is handled by the callee rather than the caller.
I leave it as an exercise for the reader to deal with calling the above, and with how to deal with short sequences (i.e. the degenerate case where one is looking at only the first or first two numbers in the sequence). :)
Note: your question sounds a lot like a homework question. If so: these are appropriate on Stack Overflow, but I can't emphasize enough that Stack Overflow should not be considered a substitute for your teacher. We are happy to provide advice and help on homework questions, but it's important that you maintain a relationship with your teacher and seek advice from them so that they better understand where you are having trouble.

Deleting from array, mirrored (strange) behavior

The title may seem a little odd, because I have no idea how to describe this in one sentence.
For the course Algorithms we have to micro-optimize some stuff, one is finding out how deleting from an array works. The assignment is delete something from an array and re-align the contents so that there are no gaps, I think it is quite similar to how std::vector::erase works from c++.
Because I like the idea of understanding everything low-level, I went a little further and tried to bench my solutions. This presented some weird results.
At first, here is a little code that I used:
class Test {
Stopwatch sw;
Obj[] objs;
public Test() {
this.sw = new Stopwatch();
this.objs = new Obj[1000000];
// Fill objs
for (int i = 0; i < objs.Length; i++) {
objs[i] = new Obj(i);
}
}
public void test() {
// Time deletion
sw.Restart();
deleteValue(400000, objs);
sw.Stop();
// Show timings
Console.WriteLine(sw.Elapsed);
}
// Delete function
// value is the to-search-for item in the list of objects
private static void deleteValue(int value, Obj[] list) {
for (int i = 0; i < list.Length; i++) {
if (list[i].Value == value) {
for (int j = i; j < list.Length - 1; j++) {
list[j] = list[j + 1];
//if (list[j + 1] == null) {
// break;
//}
}
list[list.Length - 1] = null;
break;
}
}
}
}
I would just create this class and call the test() method. I did this in a loop for 25 times.
My findings:
The first round it takes a lot longer than the other 24, I think this is because of caching, but I am not sure.
When I use a value that is in the start of the list, it has to move more items in memory than when I use a value at the end, though it still seems to take less time.
Benchtimes differ quite a bit.
When I enable the commented if, performance goes up (10-20%) even if the value I search for is almost at the end of the list (which means the if goes off a lot of times without actually being useful).
I have no idea why these things happen, is there someone who can explain (some of) them? And maybe if someone sees this who is a pro at this, where can I find more info to do this the most efficient way?
Edit after testing:
I did some testing and found some interesting results. I run the test on an array with a size of a million items, filled with a million objects. I run that 25 times and report the cumulative time in milliseconds. I do that 10 times and take the average of that as a final value.
When I run the test with my function described just above here I get a score of:
362,1
When I run it with the answer of dbc I get a score of:
846,4
So mine was faster, but then I started to experiment with a half empty empty array and things started to get weird. To get rid of the inevitable nullPointerExceptions I added an extra check to the if (thinking it would ruin a bit more of the performance) like so:
if (fromItem != null && fromItem.Value != value)
list[to++] = fromItem;
This seemed to not only work, but improve performance dramatically! Now I get a score of:
247,9
The weird thing is, the scores seem to low to be true, but sometimes spike, this is the set I took the avg from:
94, 26, 966, 36, 632, 95, 47, 35, 109, 439
So the extra evaluation seems to improve my performance, despite of doing an extra check. How is this possible?
You are using Stopwatch to time your method. This calculates the total clock time taken during your method call, which could include the time required for .Net to initially JIT your method, interruptions for garbage collection, or slowdowns caused by system loads from other processes. Noise from these sources will likely dominate noise due to cache misses.
This answer gives some suggestions as to how you can minimize some of the noise from garbage collection or other processes. To eliminate JIT noise, you should call your method once without timing it -- or show the time taken by the first call in a separate column in your results table since it will be so different. You might also consider using a proper profiler which will report exactly how much time your code used exclusive of "noise" from other threads or processes.
Finally, I'll note that your algorithm to remove matching items from an array and shift everything else down uses a nested loop, which is not necessary and will access items in the array after the matching index twice. The standard algorithm looks like this:
public static void RemoveFromArray(this Obj[] array, int value)
{
int to = 0;
for (int from = 0; from < array.Length; from++)
{
var fromItem = array[from];
if (fromItem.Value != value)
array[to++] = fromItem;
}
for (; to < array.Length; to++)
{
array[to] = default(Obj);
}
}
However, instead of using the standard algorithm you might experiment by using Array.RemoveAt() with your version, since (I believe) internally it does the removal in unmanaged code.

string.Format() parameters

How many parameters can you pass to a string.Format() method?
There must be some sort of theoretical or enforced limit on it. Is it based on the limits of the params[] type or the memory usage of the app that is using it or something else entirely?
OK, I emerge from hiding... I used the following program to verify what was going on and while Marc pointed out that a string like this "{0}{1}{2}...{2147483647}" would succeed the memory limit of 2 GiB before the argument list, my findings did't match yours. Thus the hard limit, of the number of parameters you can put in a string.Format method call has to be 107713904.
int i = 0;
long sum = 0;
while (sum < int.MaxValue)
{
var s = sizeof(char) * ("{" + i + "}").Length;
sum += s; // pseudo append
++i;
}
Console.WriteLine(i);
Console.ReadLine();
Love the discussion people!
Not as far as I know...
well, the theoretical limit would be the int32 limit for the array, but you'd hit the string length limit long before that, I guess...
Just don't go mad with it ;-p It may be better to write lots of small fragments to (for example) a file or response, than one huge hit.
edit - it looked like there was a limit in the IL (0xf4240), but apparently this isn't quite as it appears; I can make it get quite large (2^24) before I simply run out of system memory...
Update; it seems to me that the bounding point is the format string... those {1000001}{1000002} add up... a quick bit of math (below) shows that the maximum useful number of arguments we can use is 206,449,129:
long remaining = 2147483647;// max theoretical format arg length
long count = 10; // i.e. {0}-{9}
long len = 1;
int total = 0;
while (remaining >= 0) {
for(int i = 0 ; i < count && remaining >= 0; i++) {
total++;
remaining -= len + 2; // allow for {}
}
count *= 10;
len++;
}
Console.WriteLine(total - 1);
Expanding on Marc's detailed answer.
The only other limitation that is important is for the debugger. Once you pass a certain number of parameters directly to a function, the debugger becomes less functional in that method. I believe the limit is 64 parameters.
Note: This does not mean an array with 64 members, but 64 parameters passed directly to the function.
You might laugh and say "who would do this?" which is certainly a valid question. Yet LINQ makes this a lot easier than you think. Under the hood in LINQ the compiler generates a lot of code. It's possible that for a large generate SQL query where more than 64 fields are selected that you would hit this issue. Because the compiler under the hood would need to pass all of the fields to the constructor of an anonymous type.
Still a corner case.
Considering that both the limit of the Array class and the String class are the upper limit of Int32 (documented at 2,147,483,647 here: Int32 Structure), it is reasonable to believe that this value is the limit of the number string of format parameters.
Update Upon checking reflector, John is right. String.Format, using the Red Gate Reflector, shows the ff:
public static string Format(IFormatProvider provider, string format, params object[] args)
{
if ((format == null) || (args == null))
{
throw new ArgumentNullException((format == null) ? "format" : "args");
}
StringBuilder builder = new StringBuilder(format.Length + (args.Length * 8));
builder.AppendFormat(provider, format, args);
return builder.ToString();
}
The format.Length + (args.Length * 8) part of the code is enough to kill most of that number. Ergo, '2,147,483,647 = x + 8x' leaves us with x = 238,609,294 (theoretical).
It's far less than that of course; as the guys in the comments mentioned the string hitting the string length limit earlier is quite likely.
Maybe someone should just code this into a machine problem! :P

Categories

Resources