Modeling a nested object / dictionary like in JS?


#1

I’m trying to model a 2d grid of coordinates as a nested object like I would normally do in JavaScript. How can I do something like this in ReasonML? The closest thing I’ve found would be Js.Dict. Is there another way to do this using pure ReasonML / Ocaml data structures?

let grid = {};
function insert(row, col){
  grid[row] = grid[row] || {};
  grid[row][col] = true;
}

//insert coordinate with (row, col)=(2,3)
insert(2,3);

// lookup same coordinate
grid[2][3] == true

edit: I’m also open to using full bucklescript constructs like Js.Dict or something else. I’m pretty new to it, but Js.Dict seems more verbose, and defaults to having keys as strings, though maybe both of these limitations can be overcome once I understand Js.Dict a little more.


#2

The correct data structure to use really depends on the requirements. What kind of operations will you need to do on this 2d grid? Do you want it to be mutable or immutable? Do you ever want to do something like grid[2] to access an entire row as an array?

The typical Reason/OCaml data structures for modelling dictionaries are:

Worth noting that you’re actually using sparse arrays in this example. This should be doable with just the Js.Array module, e.g.:

let insert(grid, row, col) = {
  let gridRow = row
    |> Js.Array.unsafe_get(grid)
    |> Js.Nullable.toOption
    |> Js.Option.getWithDefault([||]);

  gridRow
  |> Js.Nullable.return
  |> Js.Array.unsafe_set(grid, row);
  Js.Array.unsafe_set(gridRow, col, true);
};

#3

that’s very helpful, thank you yawaramin


#4

Thanks again for the reply. I’m trying out your solution and learning some new things. You’re right that it is a sparse array. Not sure if I’m using this correctly, but I’m finding non-sparse behavior when I do this:

let grid = [||];
insert(grid, 3000, 30);
Js.log(grid->Array.length); /* returns 3001 */

#5

Yup, that’s a sparse array in JavaScript :slight_smile: https://www.oreilly.com/library/view/javascript-the-definitive/9781449393854/ch07s03.html

Note that using the functionality in the Js module means you are depending on JavaScript-specific functionality. For more portable code check out the other modules I mentioned.