2

Hello I'm new to programming in console application using C#. I am trying to create a word generator and this is my code:

for (int i = 1; i <= 4; i++)
{
    string[] fruits = { "Apple", "Banana", "Grapes", "Orange", "Cherry", "Mango" };
    Random rnd = new Random();
    int rndFruits = rnd.Next(fruits.Length);
    Console.WriteLine(fruits[rndFruits]);
}

I created a list of strings which then randomises them to print four words using for loop. The problem is I don't want it to repeat the same string again like printing banana twice or more.

Dorin Baba
  • 1,578
  • 1
  • 11
  • 23
  • (to late) https://stackoverflow.com/questions/767999/random-number-generator-only-generating-one-random-number - here a demo of the code change you will need: https://dotnetfiddle.net/0XhCo9 – Rand Random Aug 24 '21 at 16:03
  • 2
    To avoid repetition, **SHUFFLE** the word list, and then output them in the shuffled sequence. – Joel Coehoorn Aug 24 '21 at 16:04
  • 2
    though, I mean, with your username @RandRandom, I'm surprised I got the vote first... – gunr2171 Aug 24 '21 at 16:04
  • @RandRandom Yeah, be careful with dupe-hammering questions to that one; it might not be true any more - in latter versions of .net core Random is not seeded from the clock – Caius Jard Aug 24 '21 at 16:06
  • @CaiusJard - IMHO it still should be declared as dupe and the new information should be posted in the dupe, as the question is a dupe the answer could be different – Rand Random Aug 24 '21 at 16:08
  • Granted, we don't know if this code is .Net Framework or .Net Core/5. Even though [I agree it's fixed with core](https://learn.microsoft.com/en-us/dotnet/api/system.random?view=net-5.0#instantiating-the-random-number-generator), it's still sound advice. – gunr2171 Aug 24 '21 at 16:08
  • @user16742923 try this code instead: `var r = new Random(); var f = new[]{ "Apple", "Banana", "Grapes", "Orange", "Cherry", "Mango" }; foreach(string fruit in f.OrderBy(x => r.Next())) Console.WriteLine(fruit);` 9 – Caius Jard Aug 24 '21 at 16:10
  • @RandRandom no, i disagree. The world has moved on; we can't tie future questions back to old ones because you can't post a valid answer to the old question.. Add in the fact that we haven't even established that this user's complaint is even caused by declaring new Random in a loop.. They just want to not repeat values, which can happen even if a random is declared outside. I think we've jumped the dupe-gun on this one – Caius Jard Aug 24 '21 at 16:11
  • @CaiusJard - yes, you can thats why there is this https://meta.stackoverflow.com/questions/405302/introducing-outdated-answers-project – Rand Random Aug 24 '21 at 16:11
  • No, it's the *question* that is outdated. That's nothing to do with an answer. The question can remain as a valid reason why someone on eg .NET framework gets an error, but starting pointing netcore questions to it when it's not valid for netcore is not right, and posting a "I know this question is about netfw but here's an answer that is valid for netcore" isn't right to do either, because netcore doesn't necessarily suffer from the problem – Caius Jard Aug 24 '21 at 16:13
  • Well than we have to agree to disagree. Question is 100% a dupe, dupe-gun fired and hit target, feel free to re-open it and declare OP his question is outdated and he shouldn't face the problem as it is outdated, OPs own fault to have outdated problems. – Rand Random Aug 24 '21 at 16:15
  • As I said, feel free to re-open the question, nothing more for me to say. – Rand Random Aug 24 '21 at 16:28

2 Answers2

2

Here is an algorithm. It works this way. At the beginning, all of the elements are unique for us, so we will pick an element from 0 to fruits.Length. After picking it, we switch the picked element with the last one. Now we know that the last element is known for us. Let's now pick an index from 0 to fruits.Length -1. We won't take the last one in consideration because it is already known for us. Again, after retrieving an index, swap the element at current index with the one at fruits.Length -1, now we are not interested in the last 2 ones and so on.

string[] fruits = { "Apple", "Banana", "Grapes", "Orange", "Cherry", "Mango" };
Random rnd = new Random();

// This will indicate the last index for which, starting with 0, we will meet only unique elements.
int lastValidStringIndex = fruits.Length;

for (int i = 1; i <= 4; i++)
{
    int rndFruits = rnd.Next(lastValidStringIndex);
    Console.WriteLine(fruits[rndFruits]);

    // place the current element at the end of the list
    string aux = fruits[--lastValidStringIndex];
    fruits[lastValidStringIndex] = fruits[rndFruits];
    fruits[rndFruits] = aux;
}
Little simulation:
string[] fruits = { "Apple", "Banana", "Grapes", "Orange", "Cherry", "Mango" };
Random => "Banana"
Swap banana with Mango

string[] fruits = { "Apple", "Mango", "Grapes", "Orange", "Cherry", | "Banana" };
Random => "Orange"
Swap Orange with Cherry

string[] fruits = { "Apple", "Mango", "Grapes", "Cherry", | "Orange", "Banana" };

and so on

you got the idea. We don't check elements after |

Dorin Baba
  • 1,578
  • 1
  • 11
  • 23
1

The traditional way to do this is to SHUFFLE the array, and then pull from the shuffled array in sequence:

var r = new Random();
var fruits = new[]{ "Apple", "Banana", "Grapes", "Orange", "Cherry", "Mango" };

for (int i=fruits.Length-1;i>0;i--)
{
    var temp = fruits[i];
    var index = r.Next(0, i);
    fruits[i] = fruits[index];
    fruits[index] = temp;
}

for (int i = 0; i<4; i++)
{
    Console.WriteLine(fruits[i]);
}

See it work here:

https://dotnetfiddle.net/ISS1NB

Joel Coehoorn
  • 399,467
  • 113
  • 570
  • 794