0

I have to convert a python code to javascript. Now in this code we are dealing with lists like so :

    selected_element = current_list[index_col]

The index_col is an index that come from a database. I cannot really manipulate it because it has to keep the same value for another part in the code.

Some of thoses indexes are negatives (-3, -5, and so on)

So i need a simple solution to pretty keep the same syntax current_array[index_col] (I replace list by array here in order to respect the JS syntax names), that would allow me to deal with negative values.

I cannot use external libraries, all must be implemented in vanilla javascript (no lodash)

So far I found :

Accessing an element of an array through negative indexes

But is does not really help me to keep the same syntax. I must keep this syntax current_array[index_col].

louis6
  • 3
  • 2
  • The most sane way to do that is is by using [a Proxy](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy) with a get trap to watch for negative indexes. However, the requirement is pretty insane to begin with. – VLAZ Jul 17 '20 at 08:07
  • You absolutely have to use that format? What about `current_array[index_col >= 0 ? index_col : index_col + current_array.length]`? – jdaz Jul 17 '20 at 08:13
  • @jdaz : well this is because the format of that data is `VARCHAR` and I cannot modify it. so this comparaison is not possible unless i convert first. I currently try the @VLAZ and @yossefaz suggestion using proxy...even if i wish a simpler way – louis6 Jul 17 '20 at 08:24
  • 1
    @louis6 but it doesn't matter what the format in the database is. That shouldn't determine what your code looks like. If your datbase has `-5` then just change your code to `if (index < 0) index += array.length` or `array[index < 0 ? index + array.length : index]`. That will solve the problem much easier than using a proxy. – VLAZ Jul 17 '20 at 08:28
  • 1
    can you explain a bit more why you must keep the exact same syntax? sounds interesting, or there is something that we or you might have missed. – Michael Goldenberg Jul 17 '20 at 08:33
  • @MichaelGoldenberg it is a bit difficult to explain...this is because we are using a third part software that send us automaton with a fix syntax. And that software won't change the way it send us the automaton (that syntax) So i need something to handle the negative case without altering the syntax. Now the way that `proxy` stuff is dealing seems a good way since I could make some kind of middleware...but i am still trying the different suggestions here – louis6 Jul 17 '20 at 08:45
  • @louis6 How complex is the code you recieve? Could it be a viable approach to basically `code.replace(/(\w+)\[(\w+)\]/g, "getKey($1,$2)")`? *maybe a bit more refined than this little snippet* – Thomas Jul 17 '20 at 09:18
  • @Thomas : that could be a way too, but actually I got my solution with the bellow answer. I built a middleware that return proxy for each automaton request. It also helped me to handle other data structure like dict. So it was very useful. Thank you guys !! – louis6 Jul 17 '20 at 10:15

1 Answers1

0

Well, for that reason you have Proxy (docs):

const current_array = ['dog', 'pig', 'cat'];
const current_array_proxy = new Proxy(current_array, {
    get(target, prop) {
        // First check if the given index is a valis number
        if (!isNaN(prop)) {
            // If it is a valid number : be sure to not passing a string, parse it to an integer 
            prop = parseInt(prop, 10);
            if (prop < 0) {
                
                prop += target.length;
            }
        }
        return target[prop];
    }
});

Source (for this implementation and further explanation)

If you try it :

current_array_proxy[-2]; 

OUTPUT : "pig"

EDIT :

From comments :

You should handle the float number case, so replace :

if (!isNaN(prop))

by :

if(typeof prop !== "symbol" && (+prop) === (prop|0) && +prop < 0){ prop = +prop + target.length; }

If you want you can write a utils function that will return you the proxy for each single input array :


const getArrayProxy = (current_array) => new Proxy(...) //the rest is the same

jossefaz
  • 3,312
  • 4
  • 17
  • 40
  • careful when dealing with the props in proxies, Symbols don't like to be implicitely converted to a string. Second, only deal with props that are int, ignore floats: `if(typeof prop !== "symbol" && (+prop) === (prop|0) && +prop < 0){ prop = +prop + target.length; }` – Thomas Jul 17 '20 at 08:24
  • I did not know that possibility : how can I implement it without having to write this code every single time I want tu use it ? I mean : I need this syntax in the whole program... – louis6 Jul 17 '20 at 08:27
  • Write a function that accepts the array as input and returns the corresponding Proxy. – Karl Knechtel Jul 17 '20 at 08:28
  • @Thomas : good suggestion ! I forgot the float case. I will add it. @louis6 : create a utility function like `const getProxy = (current_array) => new Proxy(....)` , and call that function every time you need. You don't need to repeat yourself here. – jossefaz Jul 17 '20 at 08:32
  • If you want to be *really* strict with which get requests are used or not, [I'd do it like this](https://jsbin.com/zuwurex/3/edit?html,js,output). Check it's a valid number (handles symbols and strings like `map`), check it's it's an integer (ignores float indexes), check if it's positive (no special handling needed), check if it's negative within bounds of the array. The last one is slightly superfluous, to be quite honest and *might* lead to an incorrect behaviour `arr = ["one"]; arr[-2] = "hello"; arr.push("two"); arr[-2] //"one"` so it can be omitted. – VLAZ Jul 17 '20 at 09:00
  • 2
    @VLAZ the first line `const numericProp = Number(prop)` will throw if *anything* dares to access a `Symbol` on this `target`. I've made this mistake too often. – Thomas Jul 17 '20 at 09:11
  • @Thomas Oh...I was completely unaware that `Number` will throw an error there. I was under the assumption that it just produces `NaN` – VLAZ Jul 17 '20 at 09:19
  • @Thomas [here is my final solution, then](https://jsbin.com/zuwurex/4/edit?js,console). Passing it through `String` works. It's probably better to check `typeof prop !== "symbol"` but I'd prefer to have one set of checks and most of them rely on the prop being compared as a numeric, so it makes sense to me to convert it once and check for `NaN`. – VLAZ Jul 17 '20 at 09:24
  • @VLAZ : maybe post it as another answer here ? I would upvote it....unless you prefer me to edit my answer ? – jossefaz Jul 17 '20 at 09:43
  • Thank you guys for your answer. I finally go with the Proxy solution. I built a middleware that handle each code automaton that I received. This answer and the comments here really helped !! – louis6 Jul 17 '20 at 10:17