2

I'm making a basic Deal or No Deal game, in doing so I have to pick 10 finalists from an array, at random, without repeats.

I have my structure and arrays set out like this

public struct People
{
 public string firstname;
 public string lastname;
 public int age;
}
class Program
{
 public static People[] People1 = new People[40];
 public static People[] Finalists1 = new People[10];
 public static People[] Finalist1 = new People[1];

And my finalists method set out like this

Random rand = new Random();
for (int i = 0; i < Finalists1.Length; i++)
{
 num = rand.Next(0, People1.Length); 
 Finalists1[i].lastname = People1[num].lastname;
 Finalists1[i].firstname = People1[num].firstname;
 Finalists1[i].age = People1[num].age;
}

How can I eliminate duplicate entries, while maintaining 10 people in the array?

Patrick Hofman
158k23 gold badges270 silver badges343 bronze badges
asked Nov 11, 2016 at 9:01
6
  • 1
    Well, what do you define a duplicate? Identical firstname? LastName? Age? All three? Anyway there are dozenz of questions on StackOverflow, simply have a look for delete duplicates from collection or also select distinct values. Commented Nov 11, 2016 at 9:04
  • You can create a list of numbers that have already been picked and make sure the new number isn't in the list of picked numbers. Commented Nov 11, 2016 at 9:05
  • 1
    Sort the array in random order, pick up 10 then Commented Nov 11, 2016 at 9:05
  • I'm reasonably new to c#, but I've tried using a LINQ query and .Distinct, I tried using HashSets but I was receiving errors about converting type Assessment.People to int[] Commented Nov 11, 2016 at 9:06
  • 1
    First, you should not make People a struct but a class and second, you should call that class Person. Otherwise many people will assume your candidates are actually tribes. Commented Nov 11, 2016 at 9:09

6 Answers 6

5

Since initial array doesn't contain duplicates, you can sort it in random order and pick up 10 top items:

 Finalists1 = People1
 .OrderByDescending(item => 1) // if people have some points, bonuses etc.
 .ThenBy(item => Guid.NewGuid()) // shuffle among peers
 .Take(10) // Take top 10
 .ToArray(); // materialize as an array

If people are selected to the final are not completely random (e.g. contestant can earn points, bonuses etc.) change .OrderByDescending(item => 1), e.g.

 .OrderByDescending(item => item.Bonuses)

If you don't want to use Linq, you can just draw Peoples from urn without returning:

 private static Random random = new Random(); 
 ... 
 List<People> urn = new List<People>(People1); 
 for (int i = 0; i < Finalists1.Length; ++i) {
 int index = random.Next(0, urn.Count);
 Finalists1[i] = urn[index];
 urn.RemoveAt(index);
 } 
answered Nov 11, 2016 at 9:12
Sign up to request clarification or add additional context in comments.

2 Comments

When I go to write this out, it just takes the first ten, not in any shuffled order. Any ideas why?
@AlisterKyle: Nice catch! Wrong syntax: new Guid creates zero Guid, when Guid.NewGuid() required random one.
2

You can hold a list or hash set of numbers you have already drawn. Then just roll the dice again to get another random number.

Random rand = new Random();
HashSet<int> drawnNumbers = new HashSet<int>();
for (int i = 0; i < Finalists1.Length; i++)
{
 do
 {
 num = rand.Next(0, People1.Length);
 }
 while (drawnNumbers.Contains(num));
 Finalists1[i] = People1[num];
}
answered Nov 11, 2016 at 9:06

2 Comments

Since only 10 finalists are drawn, I think it would be better to replace HashSet by List. For maximum 10 items, a linear search is faster then a hash table loookup.
I know, but I think the idea is the same. Just wanted to use HashSet for OP to think about the impact of linear search on large data sets.
0

You can change the type of Finalists1 to a HashSet, that does not allow duplicates. Then change your loop to

while(Finalists1.Length < 10)
{
 // random pick from array People1 (you don't need to create a new one)
 num = rand.Next(0, People1.Length);
 var toAdd = People1[num];
 // add to hash-set. Object won't be added, if already existing in the set
 Finalists1.Add(toAdd);
}

You probably need to override the Equals method of class People, if you really need to create a new object to add to the hash-set.

answered Nov 11, 2016 at 9:10

Comments

0

You can group people array and select distinct that way. If you use List you can remove person from the list `var peopleArray = new People[40];

 var peopleCollection = peopleArray.GroupBy(p => new { p.age, p.firstname, p.lastname }).Select(grp => grp.FirstOrDefault()).ToList();
 var finalists = new People[10];
 var rand = new Random();
 for (var i = 0; i < finalists.Length; i++)
 {
 var index = rand.Next(0, peopleCollection.Count);
 var person = peopleCollection[index];
 finalists[i].lastname = person.lastname;
 finalists[i].firstname = person.firstname;
 finalists[i].age = person.age;
 peopleCollection.Remove(person);
 }
answered Nov 11, 2016 at 9:34

Comments

0

shuffle and take the first 10, for example

People1.Shuffle();
Finalists1= People1.Take(10).ToArray();

you can find shuffle code from StackOverflow or search for "Fisher-Yates shuffle C#" Below methods are taken from This SO Post. Read the answers for more information on why GUID is not used etc..

public static class ThreadSafeRandom
 {
 [ThreadStatic] private static Random Local;
 public static Random ThisThreadsRandom
 {
 get { return Local ?? (Local = new Random(unchecked(Environment.TickCount * 31 + Thread.CurrentThread.ManagedThreadId))); }
 }
 }
 static class MyExtensions
 {
 public static void Shuffle<T>(this IList<T> list)
 {
 int n = list.Count;
 while (n > 1)
 {
 n--;
 int k = ThreadSafeRandom.ThisThreadsRandom.Next(n + 1);
 T value = list[k];
 list[k] = list[n];
 list[n] = value;
 }
 }
 }
answered Nov 11, 2016 at 9:42

Comments

0

Swap each selected element in People1 to with the end of the array, and decrement an end-of-array index so that you're only selecting from what's left on the next iteration.

People tempPerson = new People;
int lastElem = People1.length - 1;
for (int i = 0; i < Finalists1.Length; i++)
{
 num = rand.Next(0, lastElem + 1); 
 Finalists1[i] = People1[num];
 //swap last entry in People1 with People1[num]
 tempPerson = People1[num];
 People1[num] = People1[lastElem];
 People1[lastElem] = tempPerson;
 lastElem--;
}

Sorry if there's a syntax error, I'm mostly using Java and C# these days.

BTW You don't have to set the fields individually since each array stores objects of type Person.

answered Nov 11, 2016 at 9:29

Comments

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.