Skip to content
Merged
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
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