4

Question from eloquentjavascript:

Write a function arrayToList that builds up a data structure like the previous one when given [1, 2, 3] as argument, and write a listToArray function that produces an array from a list. Also write the helper functions prepend, which takes an element and a list and creates a new list that adds the element to the front of the input list, and nth, which takes a list and a number and returns the element at the given position in the list, or undefined when there is no such element.

Can anyone explain this answer without any jargon? I can only learn by instructions.

Here is what I came up with for arrayToList: So start list null, create for loop decrementing and inside define "i" then return list.

function arrayToList(array){ //pass list as parameter
    var list = null; // don't know why we make it null
    for (var i=array.length-1; i>=0; i--)  // why -1 on the length?
        list = {value: array[i], rest:list}; //clueless
    return list;
}

what is rest:list inside the list object?

1

8 Answers 8

4

The last comment by @eloquent need to be modified:

var arr1 = [10, 20, 30];

function arrayToList(arr) {
  var list = {};

 for (var i = 0; i < arr.length; i++) {
    list.value = arr.splice(0, 1)[0];
    list.rest = (arr.length > 0) ? arrayToList(arr) : null;
 }

 return list;
}

console.clear();
console.log(  arrayToList(arr1) );
Sign up to request clarification or add additional context in comments.

Comments

2

what is rest:list inside the list object?

It creates a property rest in the object literal, and assigns to it the value of the variable list - before assigning that object to the variable list. Notice that this happens in a loop, so what it does is to take the old value and overwrite it with a new value that references the old value.

Just what you need to build that nested list structure.

var list = null; // don't know why we make it null

That's the initial value, which will be placed at the "end" of the list. If the array is empty, it will be returned, if the array has one element it will become the rest property of the object that is returned. If the array has more than one element…

why -1 on the length?

Because arrays are zero-indexed, i.e. their indices run from 0 to length-1. When we iterate backwards, we need this odd initial value and the i >= 0 comparison.

Comments

1
function arrayToList(arr) {
  var obj = {};
  for(var i = 0 ; i < arr.length; i++) {
    if(i == arr.length) {
     return obj.rest = null;
    }
    obj.value = arr.splice(0,1);
    obj.rest = arrayToList(arr);
  }
  return obj;
};

console.clear();
console.dir(arrayToList([1,2,3,4,5]));

Comments

1

my solution with recursion:

function arrayToList([...arr], n = 0){
  return (n < arr.length) ? {value: arr[n], rest: arrayToList(arr, n + 1)} : null;
} 

function listToArray({...list}, arr = []){
  arr.push(list.value);
  return (list.rest != null) ? listToArray(list.rest, arr) : arr;
}

console.log(arrayToList([10, 20]));
// → {value: 10, rest: {value: 20, rest: null}}

console.log(listToArray(arrayToList([10, 20, 30])));
// → [10, 20, 30]

Comments

0

As a disclaimer, I wanna say that I am a newbie myself and I'm here to learn things and maybe help others by doing it. Here's how I understood that the second problem it's done.

Also write a listToArray function that produces an array from a list.

The following code will work:

function listToArray(list) {
    let arr = [];
    for(; list !== null; list = list.rest) {
      arr.push(list.value);
    }
    return arr;
}

The list parameter will just hold the argument that will be inserted. In our case is: {value: 10, rest: {value: 20, rest: null}

Have in mind that the code in the Eloquent Javascript will make a list from an array with 3 elements [10, 20, 30], but for this example, we'll just use a list made from 2 elements.

On execution, the code will do the following things:

1st time(first loop):

  1. omit the initialization of the for loop(don't define any variable or do anything)
  2. check if the list is not null - it's not, because at this moment list is equal to {value: 10, rest: {value: 20, rest: null}
  3. make list(the parameter of the function) to be equal to list.rest
    • remember that .rest is just a property of the object list and that it points to another object - it will point to {value: 20, rest: null} in our case

2nd time(second loop):

  1. omit the initialization of the for loop(don't define any variable or do anything)

  2. check if the list is not null - it's not, because at this moment list is equal to {value: 20, rest: null}

  3. make list again to be equal to list.rest - but at this time it will point to rest: null, so this time the value of the list will be the value of the rest key, which is null

3rd time(third loop):

  1. omit
  2. check if the list is not null - it is in this case, so stop the execution and go to the return statement
  3. return arr

My answer is based on: https://gist.github.com/laichejl/32d98af04caa66bd195f#file-exercise-js-L18

Comments

0

I'm coming from Java background and don't understand why with the given in the book solution the end result is not just the last element of the given argument (array) but it actually created linked list?

list = {value: array[i], rest: list};

In my eyes, if you pass [1,2,3,4] as argument, then value will be sequentially equal to 1 then to 2, then to 3 and finally to 4, and there shouldn't be any links, but rest will point to the very same address as in the beginning, just now value will be equal to 4. So how this works?

This is how the program will look in java terms:

public class Main {

    public class MyList{
   
        public int value;
        public MyList rest;
    }
   
    public static void main(String[] args){
        Main main = new Main();
        MyList myList = main.new MyList();

        for (int i = 0; i < 5; i++) {
            myList.value = i;
            current.rest = myList;
        }
    }
}

And this is the output:

for(int i = 0; i < 5; i++){
    System.out.println("Value: " + myList.value + " obj. ref: " + myList.rest);
    myList = myList.rest;
}

Value: 4 obj. ref: Main$MyList@1d81eb93
Value: 4 obj. ref: Main$MyList@1d81eb93
Value: 4 obj. ref: Main$MyList@1d81eb93
Value: 4 obj. ref: Main$MyList@1d81eb93
Value: 4 obj. ref: Main$MyList@1d81eb93

To work properly, we need to create new object every time, so the for loop should look like:

MyList current = myList;

for(int i = 0; i < 5; i++) {
    MyList newList = main.new MyList();
    current.value = i;
    current.rest = newList;
    current = newList;
}

Which outputs:

Value: 0 obj. ref: Main$MyList@1d81eb93
Value: 1 obj. ref: Main$MyList@7291c18f
Value: 2 obj. ref: Main$MyList@34a245ab
Value: 3 obj. ref: Main$MyList@7cc355be
Value: 4 obj. ref: Main$MyList@6e8cf4c6

So how list reinstantiates itself in JavaScript?

Comments

0

don't know why we make it null

Probably just to make it clear that the initialized value is null (as apposed to undefined). Assigning null is not necessary either way.

why -1 on the length?

Because length is 1-based (array with 4 items has a length of 4) but indexing into an array is 0-base (array[0] returns the 1st item).

clueless

This step is creating a nested list object. The first loop creates a list with a value at that array position, the second loop creates a wrapper list with a value at that position and a pointer to the previous list, and so forth.

4 Comments

Here is the answer to the whole thing gist.github.com/laichejl/32d98af04caa66bd195f I am completely confused last chaper we were learning basics now its extremely hard
Ahh, I see. I read it wrong at first glance. It's embedding the previous list each loop inside of the rest property. What would you like explained?
Oh so rest is just a name (key/value pair of object)? It can be anything right? Why does it equal list?
It's just an arbitrarily-named key, yes. It could be called something else. It's being used to contain a pointer to the last list so that the eventual Object being returned can be crawled in order to reconstruct the original Array.
0

A simplified solution and a cleaner approach

function arrayToList(inputArray )  {
  if (!inputArray.length) {
    return null;
  }
  const [head, ...tail] = inputArray;
  return { value: head, rest: arrayToList(tail) };
}


Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.