2

I have this code:

public async Task ShowTimedCard()
{
   phrase = phrases[(int)AS.rand.Next(phrases.Count)];

It gets a random number and then selects a phrase from phrases which is a List of phrase rows. The List has items added and removed from it by a background process.

Each phrase has an Id field. I cannot remove phrases that I have used from the List for other reasons.

Sometimes ShowTimedCard picks the same phrase twice in a row so I decided to store the lastPhrase information in a static variable like this:

AS.phrase.id = phrase.id

How can I make it so if there are more than 1 items in the phrases List then it will not pick the same phrase twice in a row? I was thinking of some kind of while loop or until loop but not sure how to implement that. I guess it needs to compare the phrase.Id with the AS.phrase.id

Alan2
  • 23,493
  • 79
  • 256
  • 450
  • 3
    Remove the used phrase from the list? – Equalsk Aug 04 '17 at 16:11
  • You either need to remove the used phrase from the list, as @Equalsk said, or check to see if the selected phrase has already been used. If it has, pick another phrase. – DevelopingDeveloper Aug 04 '17 at 16:12
  • 1
    As @Equalsk says, I wish to add. Use a copy of your phrases and remove from that copy – Steve Aug 04 '17 at 16:12
  • 5
    Another alternative is to sort the phrases in a random order, then loop through them. – stuartd Aug 04 '17 at 16:14
  • I have a background process that sometimes adds or removes items from the list so I can't iterate through it. – Alan2 Aug 04 '17 at 16:16
  • I only have to not repeat the last phrase. – Alan2 Aug 04 '17 at 16:22
  • Just keep trying until you get a different one than the last one. Or you can just select the next or previous one if you hit the same one twice. – hatchet - done with SOverflow Aug 04 '17 at 16:24
  • Note that your code is not thread safe. If you pick last item and background process removes it then crash. – Adriano Repetti Aug 04 '17 at 16:27
  • 1
    If you must not pick the same value twice in a row you're looking for a [shuffle](https://stackoverflow.com/questions/5383498/shuffle). – Dour High Arch Aug 04 '17 at 16:34
  • Random can be a sequence. – Matthew Whited Aug 04 '17 at 16:59
  • @Peter Duniho This is not a duplicate of that. It only wants to not repeat the single last. Shuffle once does work as items can be added to the list. – paparazzo Aug 04 '17 at 17:37
  • @Paparazzi: a shuffle absolutely addresses the stated goal of _"it will not pick the same phrase twice in a row"_. Frankly, the question is very poor quality for a variety of reasons, including the lack of _any_ evidence of an attempt to solve the problem first, never mind a good [mcve] showing what was tried and stating a _specific_ problem. How this question got three up-votes, I have no idea (though that's a common problem in the C# tag...the worst, least-effort questions somehow often get the most up-votes). But certainly the marked duplicate does in fact answer the question. – Peter Duniho Aug 04 '17 at 17:41
  • @PeterDuniho Yes it will not let the same phase twice in a row. Problem is that will not allow the same phase twice PERIOD and that is not a goal. It also doe not address items added to the List after the shuffle. – paparazzo Aug 04 '17 at 18:03

2 Answers2

1

Show where you create rand

You should create it just once and reuse it

I bet you are creating new and not enough tick to get a new seed

OK I may have missed the question

Just shuffle the List using Yates shuffle

This is byte but you get the idea

for (byte i = (byte)(count - 1); i >= 1;  i--)
{
    byte k = (byte)rand.Next(i + 1);
    if (k != i)
    {   // exchange the values 
        curVal  = deck[i];
        deck[i] = deck[k];
        deck[k] = curVal;
    }
}

Or store the used id in a hashset

Random rand = new Random();
HashSet<int> hs = new HashSet<int>(); 
int next;
while (hs.Contains(next = rand.Next(12))) { }
hs.Add(next)

Moving target

while (next = rand.Next(12) == lastNext) { }
lastNext = next;
paparazzo
  • 44,497
  • 23
  • 105
  • 176
  • Sometimes there are only three items in the List. That's why it's easy to get the same item twice. But somehow I need to make it reselect if that happens. Not sure how to do this. – Alan2 Aug 04 '17 at 16:15
  • Sorry, I updated the question to be more clear. It's just a problem if it's twice in a row. That's why I hoped to be able do do something by storing the last card picked and comparing with the next pick and if same then doing another random pick and so on. – Alan2 Aug 04 '17 at 16:24
  • 1
    Man dude you you are a moving target – paparazzo Aug 04 '17 at 16:27
  • @Alan: you seem to know exactly what you want to do. What is stopping you from doing that check and repeat? – Chris Aug 04 '17 at 16:33
  • I don't know how to implement the check and repeat. Paparazzi's solution is good for if I don't want the same Id ever again but it's a lot more than I need. I just want to reselect if it's the same as the last phrase. I did update the question and put this in bold to try and be as clear as possible. – Alan2 Aug 04 '17 at 16:40
  • How is while (next = rand.Next(12) == lastNext) { } more than you need? – paparazzo Aug 04 '17 at 16:55
0

It sounds like what you really want to do is sort the list randomly and then you can just take consecutive items. This will ensure that you don't see any item before all the others have been displayed, but they won't be displayed in the order they were added:

// Shuffle our list of phrases, so they're in a random order
var rnd = new Random();
phrases = phrases.OrderBy(p => rnd.NextDouble()).ToList();

You can then re-shuffle the list anytime you want, like if you add new items or when you've reached the end of the list.

Here's a quick demo using integers:

// Create a list of consecutive integers and display it
var numbers = Enumerable.Range(1, 30).ToList();
Console.WriteLine("Original list:");
Console.WriteLine(string.Join(", ", numbers));

// Shuffle the list and display it again
var rnd = new Random();
numbers = numbers.OrderBy(n => rnd.NextDouble()).ToList();
Console.WriteLine("\nShuffled list:");
Console.WriteLine(string.Join(", ", numbers));

Output

enter image description here

Rufus L
  • 36,127
  • 5
  • 30
  • 43