0

How I can achieve getting the current index -5 for example. I know how to get the current index and I can subtract or add to that index, but this will cause Array out of bounds errors. Let's say the array has 15 items (index 0/14) and my current index is 2 if I will subtract 5 it will return -3. And this doesn't exist in the array. Now what I want is that when the index is 2 and I substract 5 it returns 11, so it should always loop through the array. The same applies for adding 5 obviously.

Alexei Levenkov
  • 98,904
  • 14
  • 127
  • 179
Quincy Norbert
  • 431
  • 1
  • 6
  • 18
  • Can you advise what you have tried so far? – ProgrammingLlama Apr 23 '20 at 07:26
  • I currently have only tried substracting or adding by x (5) in this case, but this was giving the out of bounds errors. In all honesty I have no clue how to know what the remainder of x is when I substract close to the 0 index or add close to the array length. – Quincy Norbert Apr 23 '20 at 07:34
  • If you just want to loop around an array, surely when the number goes out of the bounds at the lower end you can just add the length of the array, and when it goes out of the bounds at the upper end you can just subtract the length of the array. As long as the amount you add/subtract by is less than the length of the array, that should work. Write a few scenarios (starting index, resulting index, desired index) it out on paper if it helps you visualise it. – ProgrammingLlama Apr 23 '20 at 07:36
  • 1
    Damn this is so obvious, I don't understand why I completly missed this: something like if(_currentIndex < 0) {_currentIndex += _array.Lenght} and if(_currentIndex > array.Length) {_currentIndex -= _array.Lenght}should do the trick right? – Quincy Norbert Apr 23 '20 at 07:41
  • Indeed it should. – ProgrammingLlama Apr 23 '20 at 07:47

3 Answers3

2

You can create an extenstion method like this:

public static int ComputeCircularIndex(this Array arr, int i) 
{
   int N = arr.GetLength(0);
   if (i < 0) 
   {
       i = N + (i % N);
   } 
   else 
   {
       i = i % N;
   }
   return i;
}
ProgrammingLlama
  • 36,677
  • 7
  • 67
  • 86
Nick
  • 4,787
  • 2
  • 18
  • 24
  • Can you edit your answer so that it compiles? At the moment `n` (as opposed to `N`) is undefined and it doesn't return anything. – ProgrammingLlama Apr 23 '20 at 07:46
  • Nevermind, I fixed it for you, since this seems like the more elegant solution to me. – ProgrammingLlama Apr 23 '20 at 08:01
  • Would this be the eleganter solution @John? In all honesty, I don't understand how I would call this. – Quincy Norbert Apr 23 '20 at 08:11
  • 1
    @QuincyNorbert Nick has written it so that you can declare it in a static class and then simply call `myArray.ComputeCircularIndex(-5)` (see [extension methods](https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/extension-methods)), or you could simply remove the "this" and call it as `ComputeCircularIndex(myArray, -5)`. – ProgrammingLlama Apr 23 '20 at 08:13
  • That does seem very elegant, thanks for explaining! – Quincy Norbert Apr 23 '20 at 08:21
1

With the modulo operator you can achieve the secondo behavior (increment the index and cycle throw an array) pretty easily. For the first behavior, you need some additional logic. Here's the fiddle.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class MyClass: MonoBehaviour
{
   private int currentIndex = 0;

   void Increment(int value)
   {
      currentIndex += value;
      currentIndex = currentIndex % 15;
   }

   void Decrement(int value)
   {
      currentIndex -= value;

      if (currentIndex < 0)
          currentIndex = 15 + (currentIndex % 15);
   }
}
  • I assume, that when doing this, the 15 items in the array are fixed right? So when for example the array contains 20 items the % 15 adn 15 - 1 - currentIndex become % 20 and 20 - 1 - currentIndex? – Quincy Norbert Apr 23 '20 at 07:53
  • Yes, exactly. I updated the answer to make the code even more readable and easy, using modulus in each case. –  Apr 23 '20 at 08:00
1

You could use below code to assure that index is in range. It will add length of an array, so negative numbers would be in range. In case of positive, correct indexes, such addition will cause index to go out of range, thus I use mod % operator, to again make sure we are in bounds.

var numbers = Enumerable.Range(0, 15).ToArray();
var idx = 2;
var offset = 5;
idx = (idx - offset + numbers.Length) % numbers.Length;
var el = numbers[idx];

el would be equal to 12.

To assure that big values of offset will be correctly handled, you can use any multiple of numbers.Length, eg.

idx = (idx - offset + 100 * numbers.Length) % numbers.Length;
Michał Turczyn
  • 32,028
  • 14
  • 47
  • 69
  • Note that answer in the duplicate properly takes care of larger offsets (like 100) - you may want to clarify that. – Alexei Levenkov Apr 23 '20 at 08:15
  • @AlexeiLevenkov Thanks, I wish new `Index` object could handle negative indexes by default without specifying `^`, which needs positive value anyway.. – Michał Turczyn Apr 23 '20 at 08:28