This is an attempt to write a function link
that creates a linked list from an array:
function link(list) {
let next = tail = null;
for(let i = list.length-1; i >= 0; i--) {
const value = list[i];
next = { value, next };
}
let cursor = head = next;
function* iterator() {
while(cursor.next) {
yield cursor;
cursor = cursor.next
}
yield cursor;
}
return {
[Symbol.iterator]: iterator,
head,
tail,
};
}
console.log(...link([1,2,3,4]));
The iterator maintains a cursor to remember its position in the iteration.
This feels wrong and brittle.
Is it?
If so, how should the iterator be implemented here.
2 Answers 2
How about the following recursive approach
function link(list) {
if(!list.length)
return [];
let [car, ...cdr] = list;
return {
car,
cdr: link(cdr),
[Symbol.iterator]: function*() {
yield this;
yield *this.cdr;
}
}
}
ls = link([1, 2, 3, 4])
for (let t of ls)
console.log(t.car)
-
\$\begingroup\$ I think this implementation is fantastic. \$\endgroup\$52d6c6af– 52d6c6af2017年07月11日 08:56:14 +00:00Commented Jul 11, 2017 at 8:56
The number one problem with the code as originally written was that cursor was maintained at instance- rather than iterator-invocation level.
This is what "felt wrong" to me, although I could not articulate it at the time.
The following updated implementation moves the position of the cursor variable to solve this issue.
function link(list) {
let next = tail = null;
for(let i = list.length-1; i >= 0; i--) {
const value = list[i];
next = { value, next };
}
function* iterator() {
let cursor = this.head;
while(cursor.next) {
yield cursor;
cursor = cursor.next
}
yield cursor;
}
return {
[Symbol.iterator]: iterator,
head: next,
tail,
};
}
var ll = link([1,2,3,4]);
console.log(...ll);
console.log(...ll);
Explore related questions
See similar questions with these tags.
next
property of the "previous" element. Can you explain which aspect feels wrong to you? \$\endgroup\$