1

"Write a function arrayToList that builds up a list structure like"

let LL = { data: 1, next: { data: 2, next: { data: 3, next: null }}};

I understand the typical solution to this problem, where the list must be built from the inside out:

function arrToLList(arr) {
  let LList = null;
  for (let i = arr.length - 1; i >= 0; i--) {
    LList = { data: arr[i], next: LList };
  }
  return LList;
}

But my initial solution was to brute force it with a typical for loop.

function arrayToLList(arr) {
  let d = "data";
  let n = "next";

  let LList = nextNode();

  for (let i = 0; i < arr.length; i++) {
    LList[d] = arr[i];
    d = "next." + d;
    LList[n] = nextNode();
    n = "next." + n;
  }

  function nextNode() {
    return {
      data: null,
      next: null
    };
  }

  return LList;
}
  • 1
    Your solution can work if you implement one of the answers to [this question](https://stackoverflow.com/questions/6491463/accessing-nested-javascript-objects-and-arays-by-string-path) or use the lodash `get` method – Stuart Apr 05 '20 at 02:48
  • Sorry it's the lodash [set](https://lodash.com/docs/4.17.15#set) method that you need – Stuart Apr 05 '20 at 03:30

2 Answers2

0

As you are trying to access an objects parameters using strings. You can't use dot notation with string. e.g.

let data = {name:'test'};
console.log("data.name");

this is what you're attempting and it will return data.name and not the value test.

you can do the following though: data['name'] so with nested object you can do the following:

LList['next']['next']...['next']['data']

to get the n'th data element.

michmich112
  • 744
  • 4
  • 8
0

What you want to achieve is possible, but you need to customize the functionality of how getting a property works when you use bracket notation. As you mentioned, using dot notation with bracket notation won't work, you need a way to define this logic yourself. ES6 introduced Proxies which allows you to specify a set method trap for your object. Whenever you set a value on the object, the set method will be called. Using this idea, you can split the dot-notation string by . and traverse the path it returns to get your nested object. Once you have retrieved the nested object, you can set its value.

See example below:

function arrayToLList(arr) {
  let d = "data";
  let n = "next";

  let LList = nextNode();

  for (let i = 0; i < arr.length; i++) {
    LList[d] = arr[i];
    d = "next." + d;
    
    if(i < arr.length-1) // don't add null object to last node
      LList[n] = nextNode();
    n = "next." + n;
  }

  function nextNode() {
    const obj = {
      data: null,
      next: null
    };
    
    return new Proxy(obj, {
      set: function(obj, key, val) {
        const path = key.split('.');
        const last = path.pop();
        for(const prop of path) 
          obj = obj[prop];
       
        obj[last] = val;
        return true;
      }
    });
  }

  return LList;
}

console.log(arrayToLList([1, 2, 3]));

However, you don't need to use a proxy. A more straightforward way of doing this would be by creating a method such as setValueByPath(val, obj, strPath) which performs the logic in the proxy for you. Then, instead of setting your object using bracket notation, you simply call the setValueByPath(obj, strPath):

function setValudByPath(val, obj, strPath) { // pefroms same logic from proxy, just using reduce instead
  const path = strPath.split('.');
  const last = path.pop();
  path.reduce((nested, p) => nested[p], obj)[last] = val;
}

function arrayToLList(arr) {
  let d = "data";
  let n = "next";

  let LList = {data: null, next: null};

  for (let i = 0; i < arr.length; i++) {
    setValudByPath(arr[i], LList, d); // same as LList[d] = arr[i];
    d = "next." + d;
    
    if(i < arr.length-1) // don't add null object to last node
      setValudByPath({data: null, next: null}, LList, n); // same as: LList[n] = nextNode();
    n = "next." + n;
  }

  return LList;
}

console.log(arrayToLList([1, 2, 3]));
Nick Parsons
  • 45,728
  • 6
  • 46
  • 64