How to get the previous index of an array (ring buffer way) in a clean way?

55 Views Asked by At

Having an array:

array = [1, 3, 5, 78]

And treating it as a ring buffer (last element is connected with first element).

Getting the next element of any element is easy [*]:

element = 3
index = array.findIndex( e => e == 3)
nextIndex = (index + 1) % array.length // This line!

This works in case element is not found: index == -1.
This works in case element is the last index: index == 3.
This works in case element is found and is not the last index.

But if I want to find the previousIndex, I don't see any way that write separate code for the 3 different conditions:

  • the element is not found
  • the element is the first element
  • the element is found and is not the first element

Is there a one-line magic code that gives me the previousIndex in a clean and direct way?

[*] Pseudo code in JS but it can be any language

1

There are 1 best solutions below

1
derpirscher On BEST ANSWER

Your nextIndex in case of the element not being found only works, because you are exploiting a language specific property, ie findIndex will return -1 in case an element is not found. This may not be the case in other languages, thus your approach is not language agnostic because you may need a special case handling for the "not found case" in other languages.

I personally find it much easier to read, understand and maintain, if special cases (ie the element is not found) are explicitly treated, rather than exploiting some (maybe language specific) behaviour ...

Keeping that in mind, you can easily find the previousIndex of any element contained in the array, by adding array.length - 1 to its index before doing the % array.length.

The additional array.length won't change the result if index > 0 (because 1 % 4 === 5 % 4 === 9 % 4 === ... === 1). But it will shift the resulting -1 for the index = 0 to be positive and thus yield an index pointing to the last element in the array (because -1 + array.length obviously is the same as array.length - 1)

See also the following snippet (I replaced the elements in the array with letters, to reduce possible confusion in the output)

let 
  array = ["a", "b", "c", "d"],
  search = [...array, "e"];  //add another element to search for to simulate the "not found" case


for (let s of search) {
  let 
    index = array.findIndex(e => e == s),
    found = index >= 0, //or whatever findIndex may return on a non-existing element in different languages
    nextIndex = found ? (index + 1) % array.length : 0,
    previousIndex = found ? (index - 1 + array.length) % array.length : 0
    
  console.log("element", s, "   found at", index, "   next", nextIndex, "   previous", previousIndex);
}

And not even that approach is language agnostic, because it relies on array-indexes to start with 0, but there are languages, that start their arrays at index 1