Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice
  3. Join us on November 16th, 2023, between 1 pm and 9 pm CET for Ask the Experts Online on Discord and on Unity Discussions.
    Dismiss Notice

Proper way to shift elements in int[] array

Discussion in 'Scripting' started by MrDahl, May 9, 2015.

  1. MrDahl

    MrDahl

    Joined:
    Oct 29, 2013
    Posts:
    5
    C# code
    I want to shift my elements in an int array to the left by one.
    Scenario:
    [1,3,4,5] -> [3,4,5,1]

    [1,0,0,0] -> [0,0,0,1]

    etc...

    Is there any built-in/algorithm which does this?

    *EXTRA
    If I want to show the shifted array on my UI with all the leading zeroes removed but still remember the original array so when i shift it again it will remember the amount of zeroes., how would one implement that?

    Scenario:

    [1,0,0,0] (UI Value: 1000) -> (Shift) -> [0,0,0,1] (UI Value: 1) -> (Shift) -> [0,0,1,0] -> (UI Value: 10) etc..
     
    Last edited: May 9, 2015
  2. Kiwasi

    Kiwasi

    Joined:
    Dec 5, 2013
    Posts:
    16,860
    Its as simple as creating a new array and copying the elements across one by one with a for loop.

    However this is certainly an interesting way to do things. What is your use case for this? There probably is a much better option.
     
    hamsterbytedev likes this.
  3. hamsterbytedev

    hamsterbytedev

    Joined:
    Dec 9, 2014
    Posts:
    353
    I think this would be a pretty good place for an extension method if he just wants to return an array that is shifted. Should be easy enough to do with some simple for loop iteration as you said.
     
  4. hamsterbytedev

    hamsterbytedev

    Joined:
    Dec 9, 2014
    Posts:
    353
    I just threw this together really quick for you; this is what you are asking for. Just make sure you put this in a static non-generic class.

    Code (CSharp):
    1.  
    2. public static int[] Shift(this int[] myArray){
    3.         int[] tArray = new int[myArray.Length];
    4.         for(int i = 0; i < myArray.Length; i++){
    5.             if(i < myArray.Length - 1)
    6.                 tArray[i] = myArray[i + 1];
    7.             else
    8.                 tArray[i] = myArray[0];
    9.         }
    10.         return tArray;
    11.     }
    12.  
    13. //Example usage
    14.  
    15. int[] myArray = new int[]{1, 0, 0, 0};
    16. int[] tArray = myArray.Shift();
     
    leni8ec, gitlinjoss and Kiwasi like this.
  5. hamsterbytedev

    hamsterbytedev

    Joined:
    Dec 9, 2014
    Posts:
    353
    Also, for the UI thing, this method should return a string that follows the correct format. Be aware that this is not an extension and you will need to call this method from the containing class or a reference thereto

    Code (CSharp):
    1. private string StringFromIntArray (int[] myArray) {
    2.             bool nonZero = false;
    3.             string tString = string.Empty;
    4.             for (int i = 0; i < myArray.Length; i++) {
    5.                 if(!nonZero){
    6.                     if(myArray[i] != 0){
    7.                         nonZero = true;
    8.                         i--;
    9.                     }
    10.                 } else {
    11.                     tString += myArray[i].ToString();
    12.                 }
    13.              
    14.             }
    15.             return tString;
    16.         }
    Best of luck to you!
     
  6. steego

    steego

    Joined:
    Jul 15, 2010
    Posts:
    968
    I think it's faster to use Array.Copy

    Code (csharp):
    1.  
    2. public static int[] Shift(this int[] myArray)
    3. {
    4.         int[] tArray = new int[myArray.Length];
    5.         int v = myArray[0];
    6.         Array.Copy(myArray, 1, tArray, 0, myArray.Length - 1);
    7.         tArray[tArray.Length - 1] = v;
    8.         return tArray;
    9. }
    10.  
    Another option is to use a Queue<int> or LinkedList<int> both let you easily remove an item at the front and add it to the back.

    Code (csharp):
    1.  
    2. Queue<int> q = new Queue<int>( ... );
    3. int v = q.Dequeue();
    4. q.Enqueue(v);
    5.  
    6. // ------
    7.  
    8. LinkedList<int> l = new LinkedList<int>( ... );
    9. int v = l.First();
    10. l.RemoveFirst();
    11. l.AddLast(v);
    12.  
     
  7. hamsterbytedev

    hamsterbytedev

    Joined:
    Dec 9, 2014
    Posts:
    353
    Thanks for the tip. I'm going to run some testing on each of these methods and drill down which one is actually the fastest. Could be very helpful in optimization situations!
     
  8. Hikiko66

    Hikiko66

    Joined:
    May 5, 2013
    Posts:
    1,302
    If you are merely shifting data around like in your example, and not actually adding and removing data then I would simply shift an offset that points to the data. The data doesn't need to change, only the way you are looking at it.
     
    Last edited: May 10, 2015
    hamsterbytedev and Kiwasi like this.
  9. Kiwasi

    Kiwasi

    Joined:
    Dec 5, 2013
    Posts:
    16,860
    Yup. That's included in the "much better option based on use case"
     
  10. hamsterbytedev

    hamsterbytedev

    Joined:
    Dec 9, 2014
    Posts:
    353
    There's more than one way to skin a cat I suppose. I personally would not shift the data in the array. I would probably just use an offset as @NA-RA-KU stated; I'm just here to answer questions. If someone asks what is possible and I can show them how it can be done I will do just that. I can't just assume that I know everything they are trying to do and there are probably situations where you may actually want to shift data; though this probably isn't one of those cases. :)
     
  11. Kiwasi

    Kiwasi

    Joined:
    Dec 5, 2013
    Posts:
    16,860
    My first thought was simply to set up a custom data class. Use an array or list as the underlying type, and provide two different accessors, one that returns the normal data, and one that returns the shifted data.

    But there might be a reason to want a copy instead of just faking it this way.
     
  12. hamsterbytedev

    hamsterbytedev

    Joined:
    Dec 9, 2014
    Posts:
    353
    I've written a few classes that test how long it takes to complete a method or section of code and log it to the debug console if anyone is interested. Apparently my laptop takes ~420ms to populate an int[5000000] array with random numbers. :(

    I can post these if anyone is interested in using them
     
  13. hamsterbytedev

    hamsterbytedev

    Joined:
    Dec 9, 2014
    Posts:
    353
    Moreover, the copying method to shift that data executes in ~12ms and the brute force iteration takes ~65ms
     
    leni8ec likes this.
  14. hamsterbytedev

    hamsterbytedev

    Joined:
    Dec 9, 2014
    Posts:
    353
    It occurs to me that this is thread is quickly drifting away from the OP and becoming a discussion on code optimization. I've done some testing and I am going to post my findings and methodology in a new thread. I'll drop a link in here when I've finished. Cheers!
     
  15. MrDahl

    MrDahl

    Joined:
    Oct 29, 2013
    Posts:
    5
    im spawning random integer values that the player should use to hit a certain number with.
    The problem i'm addressing should be used when right clicking ANY value in the game
    I think the queue option is pretty nice. How efficient is it?
     
  16. hamsterbytedev

    hamsterbytedev

    Joined:
    Dec 9, 2014
    Posts:
    353
    Shifting of that data is VERY efficient. My findings averaged less than 1ms; however, it is not the most quickly populated. I'm working on a thread right now that gives specifics, methodology, and even the source code I used to test this. As I said, I'll link back here once I've finished the thread, so be on the lookout! In the mean time, feel free to use the queue. It's definitely a viable option.
     
    leni8ec likes this.
  17. MrDahl

    MrDahl

    Joined:
    Oct 29, 2013
    Posts:
    5
    Okay thanks
     
  18. steego

    steego

    Joined:
    Jul 15, 2010
    Posts:
    968
    How many numbers will there be? I'm guessing whichever of the methods above would be efficient enough, and you should choose the one that makes your code the most readable.

    You can do the queue even without a temporary variable
    Code (csharp):
    1. q.Enqueue(q.Dequeue())
     
    hamsterbytedev likes this.
  19. hamsterbytedev

    hamsterbytedev

    Joined:
    Dec 9, 2014
    Posts:
    353
    leni8ec likes this.