Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 12 Next capture
2021 2022 2023
1 capture
12 Jun 22 - 12 Jun 22
sparklines
Close Help
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
0
Question by Hydropulse17 · Dec 19, 2016 at 06:45 AM · arraylistsrandom.rangefor-loopindex

Comparing each random element in an array with each other element

I don't understand why my script isn't working, and I'm having a real hard time wrapping my brain around what's actually happening.

         int[] myArray = new int[numOfElements];
 
         for (int i = 0; i < myArray.Length; i++)
         {
             myArray[i] = Random.Range(0, 10);
             for (int k = i + 1; k < myArray.Length; k++)
             {
                 while (myArray[i] == myArray[k])
                 {
                      myArray[i] = Random.Range(0, 10); 
                 }
             }
         }  


I need each element in myArray to have a random value, but there can't be any identical elements. I could define each element as a random integer and compare it to every other element individually, but besides the fact that it would be an ugly mess, the array is created in the scope of a method, and the size of the array(numOfElements) will vary when ever the function is called.

If it weren't for the repeats, this script would be doing exactly what I need.

I think that's all the information you would need to tell me what I'm doing wrong, but just in case, here is a more detailed explanation:

I have a text UI object, to which a script writes 5 strings to, selecting at random from a list of strings. In order to select 5 items from the list, I'm using an int array, labeled myArray here. The value of each element in the array is an index for the list of strings. My program successfully picks 5 strings from the list and updates the text object, but it often picks some strings more than once, which I'm fairly certain is because there are equal values in the array(identical indexes that pick the same strings).

Comment
Add comment · Show 2
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Bunny83 · Dec 19, 2016 at 09:22 AM 1
Share

@$$anonymous$$ossuranta gave already a perfect answer, however i just want to address some major problems in your approach:

First of all, why does your inner loop start at i+1 and go to the end? You "fill" your array from the beginning and "i" is the current element. Only values with indices smaller than "i" have already been set but you check all the elements that hasn't been set yet and you ignore those who has been set. This makes no sense.

Even when the inner for loop is fixed from 0 to "i-1", it doesn't really ensure that the picked number is none of the previous but only that it's not equal to the latest. The while loop and the inner for loop would have to switch places to actually work. So the logic would be: while not a valid number pick a new one. Each time after you picked a new one you have to check all previous ones.

Next big problem is, what if your array element count is greater than 10 ? Right, you have an infinite loop because the 11th element (index 10) can never not equal one of the previous ones since the numbers 0 to 9 have already been used for the first 10 elements.

Checking for duplicates like that is extremely inefficient and dangerous. If you have an array with exact 10 elements, the last element would have to do countless "tries" to hit a number that hasn't been picked yet. The more numbers have been assigned the less likely you will randomly pick one of the remaining number. The extreme case is when you run out of numbers in which case you will never end.

Like $$anonymous$$ossuranta showed in his answer the easiest way to distribute numbers randomly without duplicates is to just fill in the values in order and then shuffle the elements by randomly switching places of two elements.

Just as an example how to "fix" your approach. You should never use it. I just post it as reference:

 int[] myArray = new int[numOfElements];
 
 for (int i = 0; i < myArray.Length; i++)
 {
     int number = 0;
     bool numberNotOk = true;
     while (numberNotOk)
     {
         number = Random.Range(0,10);
         numberNoOk = false; // assume we got a valid number
         for(int k = 0; k < i; k++)
         {
             if (number == myArray[k]) // duplicate, so start over and pick a new number
             {
                 numberNoOk = true;
                 break;
             }
         }
     }
     // If we got here "number" is valid so store it in the array
     myArray[i] = number;
 }

avatar image Hydropulse17 Bunny83 · Dec 19, 2016 at 10:28 PM 0
Share

Well actually, tell me if I'm wrong but I think I actually caused this issue you're speaking of while making my script more appropriate for the question. In the actual script, I wasn't doing

 Random.Range(0,10);
 
 //But rather I was doing
 
 Random.Range(0, ingredients.Count - 1);//where ingredients is a list
 

So if I understand both you and myself correctly, the infinite loop wouldn't happen unless numOfElements was greater than the amount of items in the list, which I wouldn't allow, right?

3 Replies

· Add your reply
  • Sort: 
avatar image
1
Best Answer

Answer by Kossuranta · Dec 19, 2016 at 08:47 AM

I don't really like your idea of how to accomplish what you want, because the while loop could just get stuck if random happens to be the same for many times in a row. One reason why it doesn't work is that it only checks once if the number at i is same as at k. After every time you randomize new number you would have to start the check again from the very beginning as now it could be same as some number that has already been checked.


I would do what you seem to be doing like this. It creates list of numbers from 0 to maxInt and then loops through the array making each elements value random value from the list and removing said element from list so it doesn't appear twice.

 int numOfElements = 5;
 int maxInt = 10;
 int[] myArray = new int[numOfElements];
 List<int> tempList = new List<int>();

 for (int i = 0; i < maxInt; i++)
 {
     tempList.Add(i);
 }

 int rng;
 for (int i = 0; i < myArray.Length; i++)
 {
     rng = Random.Range(0, tempList.Count);
     myArray[i] = tempList[rng];
     tempList.RemoveAt(rng);
 }



If you need your array to have numbers from 0 to n. Then I would do it like this where it creates the array and then shuffles it.

 void MyMethod()
 {
     int numOfElements = 10;
     int[] myArray = new int[numOfElements];

     for (int i = 0; i < numOfElements; i++)
     {
         myArray[i] = i;
     }
     ShuffleArray(myArray);
 }

 public static void ShuffleArray<T>(T[] arr)
 {
     for (int i = arr.Length - 1; i > 0; i--)
     {
         int r = Random.Range(0, i + 1);
         T tmp = arr[i];
         arr[i] = arr[r];
         arr[r] = tmp;
     }
 }
Comment
Add comment · Show 5 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Hydropulse17 · Dec 19, 2016 at 10:10 PM 0
Share

I managed to adapt this to my project successfully and it works perfect. But there's some funky stuff going on in your ShuffleArray method that is a bit beyond me, and I'm excited to try to understand it. Thanks to everyone, happy holidays!

avatar image Hydropulse17 · Dec 19, 2016 at 10:12 PM 0
Share

Oh yeah, ID$$anonymous$$ if it matters now that you helped me, but I came up with my script trying to adapt this to my project. http://stackoverflow.com/questions/23460367/comparing-elements-of-the-same-array-in-java

avatar image mbraley · Dec 19, 2016 at 10:47 PM 0
Share

Your shuffle would be improved by changing the for loop limit to arr.Length-2 and the limits on the call to Random.Range(0,i+1) to Random.Range(i,arr.Length-1). This would change your shuffle into a Fisher-Yates Shuffle.

link text

avatar image Bunny83 mbraley · Dec 21, 2016 at 03:50 AM 0
Share

That wouldn't "improve" anything. Actually it would make it slightly worse ( in regard to performance). He already implemented the Fisher-Yates shuffle. Specifically the first pseude code example almost one-to-one.

The advantage of the reverse iteration is that you touch the array length only once in the beginning ins$$anonymous$$d of two times each iteration.

Btw: The max parameter of the Random.Range method with int parameters is "exclusive", so subtracting one would mean you never touch the last element. Random.Range(0, 5) will return a random int in the range 0 - 4 inclusive (0, 1, 2, 3, 4)

avatar image mbraley Bunny83 · Dec 21, 2016 at 07:39 PM 0
Share

Dohhhh! your'e absolutely right. The first implementation is on the money for the Fisher-Yates shuffle from highest to lowest index.

avatar image
0

Answer by hexagonius · Dec 19, 2016 at 07:01 AM

you are initializing your array with all zeros at the start. then it iterates them and compares the current random value with the next, which is zero.
this means as long as your first random value is not zero, your equation is never true. two 3s in a row are no problem. An easier approach might be: have your index array and a list with all the numbers from 0 to the length of the array. then loop your array once and every time assign it a random value from your list from 0 to it's length and then remove it. This way, the list gets shorter and shorter and is empty at the end of the iteration, all values appearing once.

Comment
Add comment · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image
0

Answer by lamphung719 · Dec 19, 2016 at 10:55 AM

use

 for(int k =0; k < i;k++)

instead of

 for (int k = i + 1; k < myArray.Length; k++)


because all the next array element is 0.

Btw you should use the list, it's much easier to use.

  List<int> randList = new List<int>();
             int numOfElements = 5;
 
             randList.Add(UnityEngine.Random.Range(0, 10));
             for (int i = 1; i < numOfElements; i++)
             {
                 int newNum = UnityEngine.Random.Range(0, 10);
                 while(randList.Contains(newNum))
                 {
                     newNum = UnityEngine.Random.Range(0, 10);
                 }
                 randList.Add(newNum);
             }
Comment
Add comment · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this Question

Answers Answers and Comments

71 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

Assign role randomly from array 2 Answers

Copy values between two classes in two lists. 1 Answer

Outputting data to CSV file from multiple lists at specific Headers in the CSV? 0 Answers

Array index confusion - what does [i-1] do exactly??? 4 Answers

Affect every object in array. 1 Answer


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges