Iterator & Iterable Protocol
kennetpostigo opened this issue · 1 comments
Hi, I've been trying implement a few mutable data structures to gain a better understanding of data structures. I want to document and create examples on a documentation site from my learning so that others interested in the topic can learn from my experiences. So as I was working on this I started by implementing Stack
, Queue
, and LinkedList
. As I was finishing up LinkedList
and going to continue to Set
I started to think about how I've been going about iterating through my Data Structures and the Generator Iterator came into my mind. So I did some googling and found the MDN Iteration Protocols and the iterall
github repo.
I read through the MDN page and I started reading your README for this package. After reading both I'm a bit confused about the difference between @@iterator
, $$iterator
and [Symbol.iterator]
.
I want to start by implementing Iterator on my(noob) LinkedList implementation but I'm not sure exactly the way to go about it. I started out using a get()
method that would iterate and return a value based on the index you supplied. Then realized I should use get()
within insert
and delete
. When I wanted to implement indexOf()
but it iterates based on a value. Then It hit me that I'm missing something very important that would help prevent implementing iteration multiple times, the Iterator
! If I implemented it I would be able to forgo iterating in indexOf()
manually and just use Iterator
and would be able to do the same for all the other methods that need to iterate. So heres my code and not sure what to name the iterator method because I'm not sure about the differences between @@iterator
, $$iterator
and [Symbol.iterator]
:
// I'm using flow types
class Node {
data: ?any
next: ?Node;
prev: ?Node;
constructor (data: any) {
this.data = data;
this.next = null;
this.prev = null;
}
}
export class LinkedList {
head: ?Node;
tail: ?Node;
length: number;
push: Function;
...
constructor () {
this.length = 0;
this.head = null;
this.tail = null;
}
push (element: Node): void {
...
}
unshift (element: Node): void {
...
}
pop (): ?Node {
...
}
shift (): ?Node {
...
}
insert (index: number, element: Node): void {
var current: ?Node = this.get(index);
if (current) {
var newNode: Node = new Node(element),
previous: ?Node = current.prev;
if (previous) {
previous.next = newNode;
newNode.prev = previous;
newNode.next = current;
current.prev = newNode;
}
}
}
get(index: number): ?Node {
if (index > 0 && index <= this.length + 1) {
if (this.head) {
var current: Node = this.head,
previous: ?Node,
pointer: number = 0;
while(pointer++ <= index) {
if (pointer < index) {
previous = current;
if (current.next) current = current.next;
}
}
return current;
}
}
return null;
}
delete (index: number): ?Node {
var current: ?Node = this.get(index);
if (current) {
var previous = current.prev,
next = current.next;
if (previous && next) {
previous.next = next;
next.prev = previous;
this.length++;
}
}
return null;
}
// bare/not functioning implementation
[Symbol.iterator] () {
var Ll = this
return {
index: 0,
next () {
if (this.index >= Ll.length) {
return { value: undefined, done: true };
}
return { value: [someValue form Ll], done: false };
}
}
}
isEmpty (): boolean {
return this.length === 0;
}
}
Check out the API section at the bottom of the Readme that explains the differences. https://github.com/leebyron/iterall/blob/master/README.md#api
To sum up, Symbol.iterator is the official value of the Iterable protocol for ES6 environments, but not all JS environments support ES6, like most older browsers. "@@iterator" is a string that Firefox used to use before ES6. $$iterator is a variable that's set to Symbol.iterator || "@@iterator"