1 decade ago by Indiepath
I needed linked lists to manage the large amount of entities in my game - I couldn't find anything on the forums here so I decided to mash-up some code I found on the internet and make it Impact friendly. I've also added some methods so that list items can be deleted by 'object' rather than just index. For example, you can now do :
Anyway here's the code :
It's simple to use:
myList.removeObj(this);
Anyway here's the code :
/** * @Author Tim Fisher - Indiepath Ltd - Modified from source provided by Nicholas C. Zakas * */ ig.module( 'classes.doublylinkedlist' ) .defines(function(){ DoublyLinkedList = ig.Class.extend({ _head : null, _tail : null, _length : 0, init: function() { }, add: function (data){ //create a new item object, place data in var node = { data: data, next: null, prev: null }; //special case: no items in the list yet if (this._length == 0) { this._head = node; this._tail = node; } else { //attach to the tail node this._tail.next = node; node.prev = this._tail; this._tail = node; } //don't forget to update the count this._length++; }, item: function(index){ //check for out-of-bounds values if (index > -1 && index < this._length){ var current = this._head, i = 0; while(i++ < index){ current = current.next; } return current.data; } else { return null; } }, remove: function(index){ //check for out-of-bounds values if (index > -1 && index < this._length){ var current = this._head, i = 0; //special case: removing first item if (index === 0){ this._head = current.next; /* * If there's only one item in the list and you remove it, * then this._head will be null. In that case, you should * also set this._tail to be null to effectively destroy * the list. Otherwise, set the previous pointer on the new * this._head to be null. */ if (!this._head){ this._tail = null; } else { this._head.prev = null; } //special case: removing last item } else if (index === this._length -1){ current = this._tail; this._tail = current.prev; this._tail.next = null; } else { //find the right location while(i++ < index){ current = current.next; } //skip over the item to remove current.prev.next = current.next; } //decrement the length this._length--; //return the value return current.data; } else { return null; } }, removeObj : function(obj){ // Locate the object in the list var current = this._head, i = 0; // Compare the objects and find the index of the match while(this.objectEquals(obj, current.data) == false){ current = current.next; i++; if (current == null) return null; } // The object has been found so remove it using the index this.remove(i); }, size: function(){ return this._length; }, toArray: function(){ var result = [], current = this._head; while(current){ result.push(current.data); current = current.next; } return result; }, toString: function(){ return this.toArray().toString(); }, /* Comparison utility methods */ countProps : function(obj) { var count = 0; for (k in obj) { if (obj.hasOwnProperty(k)) { count++; } } return count; }, objectEquals : function(v1, v2) { // Compare the types if (typeof(v1) !== typeof(v2)) { return false; } // Compare the function, if it's a function if (typeof(v1) === "function") { return v1.toString() === v2.toString(); } // Compare the objects - count the properties and then enumerate the keys if (v1 instanceof Object && v2 instanceof Object) { if (this.countProps(v1) !== this.countProps(v2)) { return false; } var r = true; for (k in v1) { r = this.objectEquals(v1[k], v2[k]); if (!r) { return false; } } return true; } else { // Do a standard compare return v1 === v2; } } }); });
It's simple to use:
var list = new DoublyLinkedList(); list.add(1); list.add(3); list.add({hello:'mum'}); list.add(2); console.log(list.toArray()); list.removeObj({hello:'mum'}); console.log(list.toArray());