Skip to content

Commit

Permalink
Merge pull request #10 from eyas-ranjous/delete_by_value
Browse files Browse the repository at this point in the history
add deleteByValue
  • Loading branch information
eyas-ranjous authored Feb 9, 2022
2 parents f9e5895 + f6400b5 commit 8e12906
Show file tree
Hide file tree
Showing 9 changed files with 172 additions and 116 deletions.
17 changes: 14 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,25 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]
## [1.0.2] - 2021-JUN-24

## [2.0.0] - 2022-feb-09
### Changed
- deleteByKey to delete item by its key
- deleteByValue to delete items by a matching criteria.
- internal cleanup.

## [1.0.2] - 2021-jun-24
### Fixed
- index.d.ts

## [1.0.2] - 2021-jun-24
### Fixed
- index.d.ts

## [1.0.1] - 2021-MAY-12
## [1.0.1] - 2021-may-12
### Fixed
- README

## [1.0.0] - 2021-MAY-12
## [1.0.0] - 2021-may-12
### Added
- v1
62 changes: 36 additions & 26 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ An implementation of the round robin as a data structure. Two strategies are imp
* [add(item)](#additem)
* [count()](#count)
* [next()](#next)
* [completedRounds()](#completedrounds)
* [delete(key)](#deletekey)
* [deleteByKey(key)](#deletebykeykey)
* [deleteByValue(cb)](#deletebyvaluecb)
* [reset()](#reset)
* [clear()](#clear)
* [Build](#build)
Expand Down Expand Up @@ -181,61 +181,73 @@ console.log(randomTable.next()); // { key: 3, value: 25 }
console.log(randomTable.next()); // { key: 1, value: 10 }
```

### completedRounds()
returns the number of completed rounds.
### deleteByKey(key)
deletes an item by its key from the table.

<table>
<tr>
<th align="center">return</th>
</tr>
<tr>
<td align="center">number</td>
<td align="center">boolean</td>
</tr>
</table>

```js
console.log(sequentialTable.completedRounds()); // 1
sequentialTable.deleteByKey(0);
sequentialTable.deleteByKey(2);
console.log(sequentialTable.next()); // { key: 1, value: 'T2' }
console.log(sequentialTable.next()); // { key: 3, value: 'T4' }
console.log(sequentialTable.next()); // { key: 1, value: 'T2' }

console.log(randomTable.completedRounds()); // 1
randomTable.deleteByKey(0);
randomTable.deleteByKey(2);
console.log(randomTable.next()); // { key: 3, value: 25 }
console.log(randomTable.next()); // { key: 1, value: 10 }
console.log(randomTable.next()); // { key: 3, value: 25 }
```

### delete(key)
deletes an item from the table by its key.
### deleteByValue(cb)
deletes items with values that match a criteria from the table and returns the number of deleted items.

<table>
<tr>
<th align="center">params</th>
<th align="center">return</th>
</tr>
<tr>
<td align="center">boolean</td>
<td align="center">cb: (value: T) => boolean</td>
<td align="center">number</td>
</tr>
</table>

```js
sequentialTable.delete(0);
sequentialTable.delete(2);
console.log(sequentialTable.next()); // { key: 1, value: 'T2' }
console.log(sequentialTable.next()); // { key: 3, value: 'T4' }
console.log(sequentialTable.next()); // { key: 1, value: 'T2' }

randomTable.delete(0);
randomTable.delete(2);
console.log(randomTable.next()); // { key: 3, value: 25 }
console.log(randomTable.next()); // { key: 1, value: 10 }
console.log(randomTable.next()); // { key: 3, value: 25 }
const seqTable = new SequentialRoundRobin<number>([2, 3, 5, 6, 7, 10]);
const ranTable = new RandomRoundRobin<{ id: string }>([
{ id: '123' },
{ id: 'id456' },
{ id: '456' },
{ id: 'id780' }
]);

const d1 = seqTable.deleteByValue((n) => n % 2 === 1); // 3
console.log(seqTable.next(), seqTable.next(), seqTable.next())
// { key: 0, value: 2 } { key: 3, value: 6 } { key: 5, value: 10 }

const d2 = ranTable.deleteByValue((obj) => obj.id.indexOf('id') === 0); // 2
console.log(ranTable.next(), ranTable.next())
// { key: 2, value: { id: '456' } } { key: 0, value: { id: '123' } }
```

### reset()
resets the table with the intial items and clears completed rounds.
resets the table with the intial values.

```js
sequentialTable.reset();
console.log(sequentialTable.count()); // 3
console.log(sequentialTable.completedRounds()); // 0

randomTable.reset();
console.log(randomTable.count()); // 3
console.log(randomTable.completedRounds()); // 0
```

### clear()
Expand All @@ -244,11 +256,9 @@ clears all values in the table.
```js
sequentialTable.clear();
console.log(sequentialTable.count()); // 0
console.log(sequentialTable.completedRounds()); // 0

randomTable.clear();
console.log(randomTable.count()); // 0
console.log(randomTable.completedRounds()); // 0
```

## Build
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "round-robin-js",
"version": "1.0.2",
"version": "2.0.0",
"description": "an implementation of round robin as a data structure",
"main": "index.js",
"scripts": {
Expand All @@ -20,7 +20,7 @@
},
"homepage": "https://github.com/eyas-ranjous/round-robin-js#readme",
"dependencies": {
"@datastructures-js/linked-list": "^5.0.1"
"@datastructures-js/linked-list": "^5.1.1"
},
"devDependencies": {
"chai": "^4.2.0",
Expand Down
71 changes: 39 additions & 32 deletions src/RandomRoundRobin.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@ const RoundRobin = require('./RoundRobin');
class RandomRoundRobin extends RoundRobin {
/**
* @constructor
* @param {array} items
* @param {array} values
*/
constructor(items) {
super(items);
constructor(values) {
super(values);
this._init();
}

Expand All @@ -24,66 +24,77 @@ class RandomRoundRobin extends RoundRobin {
*/
_init() {
this._items = new Map();
this._keys = new Set();
this._round = new Set();
this._initialItems.forEach((item) => this.add(item));
this._initialValues.forEach((value) => this.add(value));
}

/**
* Adds an item and memoizes its key for random selection
* Adds a value to the table
* @public
* @return {object}
* @return {any} value
*/
add(item) {
add(value) {
const key = this._currentkey;
this._items.set(key, { key, value: item });
this._keys.add(key);
this._items.set(key, { key, value });
this._currentkey++;
return this._items.get(key);
}

/**
* Deletes an item with its key from the table
* Deletes an item by its key from the table
* @public
* @param {number} key
* @return {boolean}
*/
delete(key) {
if (!this._keys.has(key)) {
deleteByKey(key) {
if (!this._items.has(key)) {
return false;
}

if (this._currentTurn && this._currentTurn.key === key) {
this._currentTurn = this._selectNextItem();
if (this._currentTurn === null) {
this._completedRounds += 1;
}
this._currentTurn = this._nextTurn();
}

this._keys.delete(key);
this._round.delete(key);

return this._items.delete(key);
}

/**
* Deletes items that their values match a criteria
* @public
* @param {function} cb
* @return {number}
*/
deleteByValue(cb) {
let deleted = 0;
this._items.forEach(({ key, value }) => {
if (cb(value)) {
this.deleteByKey(key);
deleted += 1;
}
});
return deleted;
}

/**
* Selects the next item's key from the round
* @public
* @return {object}
*/
_selectNextItem() {
_nextTurn() {
if (this._currentTurn === null) {
this._round = new Set(this._keys);
const keys = Array.from(this._items.keys());
this._round = new Set(keys);
}

const keys = Array.from(this._round);
if (keys.length === 0) {
if (this._round.size === 0) {
return null;
}

const randomKey = keys[Math.floor(Math.random() * keys.length)];
this._round.delete(randomKey);
return this._items.get(randomKey);
const roundKeys = Array.from(this._round);
const selectedKey = roundKeys[Math.floor(Math.random() * roundKeys.length)];
this._round.delete(selectedKey);
return this._items.get(selectedKey);
}

/**
Expand All @@ -97,15 +108,11 @@ class RandomRoundRobin extends RoundRobin {
}

if (this._currentTurn === null) {
this._currentTurn = this._selectNextItem();
this._currentTurn = this._nextTurn();
}

const item = this._currentTurn;
this._currentTurn = this._selectNextItem();
if (this._currentTurn === null) {
this._completedRounds += 1;
}

this._currentTurn = this._nextTurn();
return item;
}

Expand Down
7 changes: 4 additions & 3 deletions src/RoundRobin.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@ export interface RoundRobinItem<T> {
}

export class RoundRobin<T> {
constructor(items?: T[]);
add(item: T): RoundRobinItem<T>;
delete(key: number): boolean;
constructor(values?: T[]);
add(value: T): RoundRobinItem<T>;
deleteByKey(key: number): boolean;
deleteByValue(cb: (value: T) => boolean): number;
next(): RoundRobinItem<T>;
count(): number;
completedRounds(): number;
Expand Down
22 changes: 6 additions & 16 deletions src/RoundRobin.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,35 +12,25 @@
class RoundRobin {
/**
* @constructor
* @param {array} items
* @param {array} values
*/
constructor(items = []) {
if (items && !Array.isArray(items)) {
throw new Error('items must be an array');
constructor(values = []) {
if (values && !Array.isArray(values)) {
throw new Error('RoundRobin constructor: values must be an array');
}
this._initialItems = items;

this._initialValues = values;
this._currentkey = 0;
this._completedRounds = 0;
this._currentTurn = null;
}

/**
* Returns number of completed round of turns
* @public
* @return {number}
*/
completedRounds() {
return this._completedRounds;
}

/**
* Clears the table
* @public
* @return {RoundRobin}
*/
clear() {
this._currentkey = 0;
this._completedRounds = 0;
this._currentTurn = null;
return this;
}
Expand Down
Loading

0 comments on commit 8e12906

Please sign in to comment.