Skip to content

Commit d56f2c7

Browse files
committed
feat(core): add dropByValueAll to LinkedList
1 parent 75a13a0 commit d56f2c7

File tree

2 files changed

+102
-0
lines changed

2 files changed

+102
-0
lines changed

npm/ng-packs/packages/core/src/lib/tests/linked-list.spec.ts

+89
Original file line numberDiff line numberDiff line change
@@ -538,6 +538,95 @@ describe('Linked List (Doubly)', () => {
538538
expect(list.tail.previous.previous.value).toBe('a');
539539
});
540540
});
541+
542+
describe('#byValueAll', () => {
543+
it('should remove all nodes with given value', () => {
544+
list.add('a').tail();
545+
list.add('x').tail();
546+
list.add('b').tail();
547+
list.add('x').tail();
548+
list.add('c').tail();
549+
550+
// "a" <-> "x" <-> "b" <-> "x" <-> "c"
551+
552+
const dropped = list.drop().byValueAll('x');
553+
554+
// "a" <-> "b" <-> "c"
555+
556+
expect(dropped.length).toBe(2);
557+
expect(dropped[0].value).toEqual('x');
558+
expect(dropped[0].previous.value).toEqual('a');
559+
expect(dropped[0].next.value).toEqual('b');
560+
expect(dropped[1].value).toEqual('x');
561+
expect(dropped[1].previous.value).toEqual('b');
562+
expect(dropped[1].next.value).toEqual('c');
563+
564+
expect(list.length).toBe(3);
565+
expect(list.head.value).toBe('a');
566+
expect(list.head.next.value).toBe('b');
567+
expect(list.head.next.next.value).toBe('c');
568+
expect(list.tail.value).toBe('c');
569+
expect(list.tail.previous.value).toBe('b');
570+
expect(list.tail.previous.previous.value).toBe('a');
571+
});
572+
573+
it('should be able to receive a custom compareFn', () => {
574+
list.add({ x: 1 }).tail();
575+
list.add({ x: 0 }).tail();
576+
list.add({ x: 2 }).tail();
577+
list.add({ x: 0 }).tail();
578+
list.add({ x: 3 }).tail();
579+
580+
// {"x":1} <-> {"x":0} <-> {"x":2} <-> {"x":0} <-> {"x":3}
581+
582+
const dropped = list.drop().byValueAll({ x: 0 }, (v1: X, v2: X) => v1.x === v2.x);
583+
584+
// {"x":1} <-> {"x":2} <-> {"x":3}
585+
586+
expect(dropped.length).toBe(2);
587+
expect(dropped[0].value.x).toEqual(0);
588+
expect(dropped[0].previous.value.x).toEqual(1);
589+
expect(dropped[0].next.value.x).toEqual(2);
590+
expect(dropped[1].value.x).toEqual(0);
591+
expect(dropped[1].previous.value.x).toEqual(2);
592+
expect(dropped[1].next.value.x).toEqual(3);
593+
594+
expect(list.length).toBe(3);
595+
expect(list.head.value.x).toBe(1);
596+
expect(list.head.next.value.x).toBe(2);
597+
expect(list.head.next.next.value.x).toBe(3);
598+
expect(list.tail.value.x).toBe(3);
599+
expect(list.tail.previous.value.x).toBe(2);
600+
expect(list.tail.previous.previous.value.x).toBe(1);
601+
});
602+
603+
it('should return empty array when list is empty', () => {
604+
const dropped = list.drop().byValueAll('x');
605+
expect(dropped).toEqual([]);
606+
});
607+
608+
it('should return empty array when given value is not found', () => {
609+
list.add('a').tail();
610+
list.add('b').tail();
611+
list.add('c').tail();
612+
613+
// "a" <-> "b" <-> "c"
614+
615+
const dropped = list.drop().byValueAll('x');
616+
617+
// "a" <-> "b" <-> "c"
618+
619+
expect(dropped).toEqual([]);
620+
621+
expect(list.length).toBe(3);
622+
expect(list.head.value).toBe('a');
623+
expect(list.head.next.value).toBe('b');
624+
expect(list.head.next.next.value).toBe('c');
625+
expect(list.tail.value).toBe('c');
626+
expect(list.tail.previous.value).toBe('b');
627+
expect(list.tail.previous.previous.value).toBe('a');
628+
});
629+
});
541630
});
542631

543632
describe('#get', () => {

npm/ng-packs/packages/core/src/lib/utils/linked-list.ts

+13
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@ export class LinkedList<T = any> {
117117
return {
118118
byIndex: (position: number) => this.dropByIndex(position),
119119
byValue: (value: T, compareFn = compare) => this.dropByValue(value, compareFn),
120+
byValueAll: (value: T, compareFn = compare) => this.dropByValueAll(value, compareFn),
120121
head: () => this.dropHead(),
121122
tail: () => this.dropTail(),
122123
};
@@ -148,6 +149,18 @@ export class LinkedList<T = any> {
148149
return this.dropByIndex(position);
149150
}
150151

152+
dropByValueAll(value: T, compareFn = compare): ListNode<T>[] {
153+
const dropped: ListNode<T>[] = [];
154+
155+
for (let current = this.first, position = 0; current; position += 1, current = current.next) {
156+
if (compareFn(current.value, value)) {
157+
dropped.push(this.dropByIndex(position - dropped.length));
158+
}
159+
}
160+
161+
return dropped;
162+
}
163+
151164
dropHead(): ListNode<T> | undefined {
152165
const head = this.first;
153166

0 commit comments

Comments
 (0)