Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add deleteAll #71

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -461,6 +461,27 @@ Collections: (Array+, List, Deque, Set, Map, MultiMap, SortedSet, SortedMap,
LruSet, LruMap, LfuSet, LfuMap, SortedArray, SortedArraySet, SortedArrayMap,
FastSet, FastMap, Dict, Heap)

### deleteAll(value, opt_equals)

Deletes every value equivalent to the given value from the collection.
For sets, this is equivalent to delete, but for lists, arrays, and sorted
arrays, may delete more than one value.
For lists and arrays, this involves a linear search, from the beginning,
splicing out each node as it is traversed.
For sorted arrays, there is a mode for the provided equals and the intrinsic
equals.
The provided equals falls back to the linear search provided by the underlying
array.
However, if deleteAll uses its intrinsic order and equivalence, it can guarantee
that all intrinsic values are within a range from the first to the last
equivalent value, so it can splice all equivalent values at once, using a binary
search to find the first equivalent value, and a linear search to find the last..
The method is not implemented on Deque or Heap since random manipulation of
internal content is out of scope for these collections.

Collections: (Array+, List, Set, SortedSet, LruSet, LfuSet, SortedArray,
SortedArraySet)

### indexOf(value)

Returns the position in the collection of a value, or `-1` if it is
Expand Down
1 change: 1 addition & 0 deletions checklist.csv
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ Order,Method,Interface,Set,SortedSet,LruSet,LfuSet,SortedArraySet,FastSet,ArrayS
0d2a1b,"delete(value, equals)",order,(alt),(alt),(alt),(alt),(alt),(alt),(alt),(alt),(alt),(alt),(alt),(alt),(alt),(alt),(alt),List,(na),(alt),(alt),(na),Array,(alt),,,,
0d2a2,delete(key or index),map,(alt),(alt),(alt),(alt),(alt),(alt),(alt),GenericMap,GenericMap,GenericMap,GenericMap,GenericMap,GenericMap,Dict,WeakMap,(alt),(na),(alt),(alt),(na),(alt),(todo maybe for the property change),,,GenericMap,
0d2b1,"deleteEach(keys or values, optional equals)",collection,GenericCollection,GenericCollection,GenericCollection,GenericCollection,GenericCollection,GenericCollection,(alt),GenericCollection,GenericCollection,GenericCollection,GenericCollection,GenericCollection,GenericCollection,GenericCollection,(todo maybe),GenericCollection,(na),GenericCollection,GenericCollection,(na),GenericCollection,(todo maybe),GenericCollection,,,
0d2c,"deleteAll(value, equals)",(na),GenericSet,GenericSet,GenericSet,GenericSet,GenericSet,GenericSet,GenericSet,(na),(na),(na),(na),(na),(na),(na),(na),List,(na),(na),SortedArray,(na),Array,(na),,GenericSet,,
1a1,"indexOf(value, index)",array,(na),SortedSet,(na),(na),SortedArray O(log length),(na),(todo),(na),(na),(na),(na),(na),(na),(na),(na),(todo),Deque,(na),SortedArray O(log length),(todo),(spec),(na),,,,
1a2,"lastIndexOf(value, index)",order,(na),(na because uniqueness guarantees equivalence to indexOf),(na),(na),SortedArray O(log length),(na),(todo),(na),(na),(na),(na),(na),(na),(na),(na),(todo),Deque,(na),SortedArray O(log length),(todo),(spec),(na),,,,
1b1,"find(callback, thisp, index)",order,(todo),(todo),(na),(na),(todo),(na),(todo),(na),(na),(na),(na),(na),(na),(na),(na),(todo),(todo),(na),(todo),(todo),ES6,(na),,,,
Expand Down
7 changes: 7 additions & 0 deletions generic-set.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,13 @@ GenericSet.prototype.symmetricDifference = function (that) {
return union.difference(intersection);
};

GenericSet.prototype.deleteAll = function (value) {
// deleteAll is equivalent to delete for sets since they guarantee that
// only one value exists for an equivalence class, but deleteAll returns
// the count of deleted values instead of whether a value was deleted.
return +this["delete"](value);
};

GenericSet.prototype.equals = function (that, equals) {
var self = this;
return (
Expand Down
20 changes: 18 additions & 2 deletions list.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ List.prototype.find = function (value, equals, index) {
var head = this.head;
var at = this.scan(index, head.next);
while (at !== head) {
if (equals(at.value, value)) {
if (equals(value, at.value)) {
return at;
}
at = at.next;
Expand All @@ -49,7 +49,7 @@ List.prototype.findLast = function (value, equals, index) {
var head = this.head;
var at = this.scan(index, head.prev);
while (at !== head) {
if (equals(at.value, value)) {
if (equals(value, at.value)) {
return at;
}
at = at.prev;
Expand Down Expand Up @@ -88,6 +88,22 @@ List.prototype['delete'] = function (value, equals) {
return false;
};

List.prototype.deleteAll = function (value, equals) {
equals = equals || this.contentEquals;
var head = this.head;
var at = head.next;
var count = 0;
while (at !== head) {
if (equals(value, at.value)) {
at["delete"]();
count++;
}
at = at.next;
}
this.length -= count;
return count;
};

List.prototype.clear = function () {
var plus, minus;
if (this.dispatchesRangeChanges) {
Expand Down
14 changes: 14 additions & 0 deletions shim-array.js
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,20 @@ define("delete", function (value, equals) {
return false;
});

define("deleteAll", function (value, equals) {
equals = equals || this.contentEquals || Object.equals;
var count = 0;
for (var index = 0; index < this.length;) {
if (equals(value, this[index])) {
this.swap(index, 1);
count++;
} else {
index++;
}
}
return count;
});

define("find", function (value, equals) {
equals = equals || this.contentEquals || Object.equals;
for (var index = 0; index < this.length; index++) {
Expand Down
30 changes: 30 additions & 0 deletions sorted-array.js
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,34 @@ SortedArray.prototype["delete"] = function (value, equals) {
}
};

SortedArray.prototype.deleteAll = function (value, equals) {
if (equals) {
var count = this.array.deleteAll(value, equals);
this.length -= count;
return count;
} else {
var start = searchFirst(this.array, value, this.contentCompare, this.contentEquals);
if (start !== -1) {
var end = start;
while (this.contentEquals(value, this.array[end])) {
end++;
}
var minus = this.slice(start, end);
if (this.dispatchesRangeChanges) {
this.dispatchBeforeRangeChange([], minus, start);
}
this.array.splice(start, minus.length);
this.length -= minus.length;
if (this.dispatchesRangeChanges) {
this.dispatchRangeChange([], minus, start);
}
return minus.length;
} else {
return 0;
}
}
};

SortedArray.prototype.indexOf = function (value) {
return searchFirst(this.array, value, this.contentCompare, this.contentEquals);
};
Expand All @@ -173,6 +201,7 @@ SortedArray.prototype.find = function (value, equals, index) {
if (index) {
throw new Error("SortedArray#find does not support third argument: index");
}
// TODO support initial partition index
return searchFirst(this.array, value, this.contentCompare, this.contentEquals);
};

Expand All @@ -183,6 +212,7 @@ SortedArray.prototype.findLast = function (value, equals, index) {
if (index) {
throw new Error("SortedArray#findLast does not support third argument: index");
}
// TODO support initial partition index
return searchLast(this.array, value, this.contentCompare, this.contentEquals);
};

Expand Down
8 changes: 8 additions & 0 deletions spec/array-spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -286,5 +286,13 @@ describe("Array", function () {

});

describe("deleteAll", function () {
it("should delete a range of equivalent values", function () {
var array = [1, 1, 1, 2, 2, 2, 3, 3, 3];
expect(array.deleteAll(2)).toBe(3);
expect(array).toEqual([1, 1, 1, 3, 3, 3]);
});
});

});

14 changes: 14 additions & 0 deletions spec/list-spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,20 @@ describe("List", function () {

});

describe("deleteAll", function () {
it("deletes all equivalent values", function () {
var anyEven = {
equals: function (that) {
return that % 2 === 0;
}
};
var collection = List([1, 2, 3, 4, 5]);
expect(collection.deleteAll(anyEven)).toBe(2);
expect(collection.toArray()).toEqual([1, 3, 5]);
expect(collection.length).toBe(3);
});
});

describeRangeChanges(List);

});
Expand Down
6 changes: 6 additions & 0 deletions spec/set.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,12 @@ function describeSet(Set, sorted) {
expect(set.has(object)).toBe(false);
});

it("can deleteAll", function () {
var set = new Set([0]);
expect(set.deleteAll(0)).toBe(1);
expect(set.deleteAll(0)).toBe(0);
});

if (!sorted) {
it("can add and delete objects from the same bucket", function () {
var a = {id: 0}, b = {id: 1};
Expand Down
23 changes: 21 additions & 2 deletions spec/sorted-array-spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,27 @@ describe("SortedArray", function () {
});

describe("non-uniqueness", function () {
var array = SortedArray([1, 2, 3, 1, 2, 3]);
expect(array.slice()).toEqual([1, 1, 2, 2, 3, 3]);
it("should retain non-unique values", function () {
var array = SortedArray([1, 2, 3, 1, 2, 3]);
expect(array.slice()).toEqual([1, 1, 2, 2, 3, 3]);
});
});

describe("deleteAll", function () {
it("should delete a range of equivalent values", function () {
var array = SortedArray([1, 1, 1, 2, 2, 2, 3, 3, 3]);
expect(array.deleteAll(2)).toBe(3);
expect(array.toArray()).toEqual([1, 1, 1, 3, 3, 3]);
});
it("deletes all equivalent values for an alternate relation", function () {
var equivalent = function (a, b) {
return a % 2 === b % 2;
};
var collection = SortedArray([1, 2, 3, 4, 5]);
expect(collection.deleteAll(2, equivalent)).toBe(2);
expect(collection.toArray()).toEqual([1, 3, 5]);
expect(collection.length).toBe(3);
});
});

// TODO test stability
Expand Down