Permalink
Please
sign in to comment.
Showing
with
135 additions
and 2 deletions.
- +85 −1 src/__tests__/index.spec.ts
- +50 −1 src/index.ts
@@ -1 +1,85 @@ | ||
xit('Jest working', () => {}); | ||
import {hotReddit, bestReddit, hotYCombinator} from '..'; | ||
|
||
describe('hotReddit', () => { | ||
it('gives higher rating to never content', async () => { | ||
const ts = Date.now(); | ||
const score1 = hotReddit(10, 2, ts - 10000); | ||
const score2 = hotReddit(10, 2, ts); | ||
|
||
expect(score2).toBeGreaterThan(score1); | ||
}); | ||
|
||
it('gives higher rating to content with more up votes', async () => { | ||
const ts = Date.now(); | ||
const score1 = hotReddit(12, 2, ts); | ||
const score2 = hotReddit(10, 2, ts); | ||
|
||
expect(score1).toBeGreaterThan(score2); | ||
}); | ||
|
||
it('gives higher rating to content with less down votes', async () => { | ||
const ts = Date.now(); | ||
const score1 = hotReddit(12, 2, ts); | ||
const score2 = hotReddit(12, 1, ts); | ||
|
||
expect(score2).toBeGreaterThan(score1); | ||
}); | ||
|
||
it('gives higher rating to content with more up votes - 2', async () => { | ||
const ts = Date.now(); | ||
const score1 = hotReddit(1, 0, ts); | ||
const score2 = hotReddit(2, 0, ts); | ||
|
||
expect(score2).toBeGreaterThan(score1); | ||
}); | ||
}); | ||
|
||
describe('bestReddit', () => { | ||
it('gives higher score to content with more up votes', async () => { | ||
const score1 = bestReddit(11, 2); | ||
const score2 = bestReddit(10, 2); | ||
|
||
expect(score1).toBeGreaterThan(score2); | ||
}); | ||
|
||
it('gives higher score to content with less down votes', async () => { | ||
const score1 = bestReddit(1000, 10); | ||
const score2 = bestReddit(1000, 11); | ||
|
||
expect(score1).toBeGreaterThan(score2); | ||
}); | ||
}); | ||
|
||
describe('hotYCombinator', () => { | ||
it('gives higher score to more recent content', async () => { | ||
const ts = Date.now(); | ||
const score1 = hotYCombinator(10, ts); | ||
const score2 = hotYCombinator(10, ts - 10000); | ||
|
||
expect(score1).toBeGreaterThan(score2); | ||
}); | ||
|
||
it('gives higher score to content with more up votes', async () => { | ||
const ts = Date.now(); | ||
const score1 = hotYCombinator(110, ts); | ||
const score2 = hotYCombinator(111, ts); | ||
|
||
expect(score2).toBeGreaterThan(score1); | ||
}); | ||
|
||
it('gives higher score to content with more up votes - 2', async () => { | ||
const ts = Date.now(); | ||
const score1 = hotYCombinator(0, ts); | ||
const score2 = hotYCombinator(111, ts); | ||
|
||
expect(score2).toBeGreaterThan(score1); | ||
}); | ||
|
||
it('gives higher score to content with more up votes - 3', async () => { | ||
const ts = Date.now(); | ||
const score1 = hotYCombinator(1, ts); | ||
const score2 = hotYCombinator(111, ts); | ||
|
||
expect(score2).toBeGreaterThan(score1); | ||
}); | ||
}); |
@@ -1 +1,50 @@ | ||
console.log('Hello world!'); // tslint:disable-line no-console | ||
/** | ||
* Reddit's hot content scoring function. Used for raking higher most recent and | ||
* highest voted content. More recent content items get higher score automatically. | ||
* | ||
* - See: https://medium.com/hacking-and-gonzo/how-reddit-ranking-algorithms-work-ef111e33d0d9 | ||
* | ||
* @param ups Number of up votes. | ||
* @param downs Number of down votes. | ||
* @param ts Timestamp in milliseconds when content was created. | ||
*/ | ||
export function hotReddit (ups: number, downs: number, ts = Date.now()) { | ||
const s = ups - downs; | ||
const order = Math.log(Math.max(Math.abs(s), 1)) / Math.LN10; | ||
const sign = s > 0 ? 1 : (s < 0 ? -1 : 0); | ||
const seconds = (ts / 1e3) - 1134028003; | ||
return sign * order + seconds / 45000; | ||
} | ||
|
||
/** | ||
* YCombinator's hot content scoring formula. Does not require down votes. | ||
* | ||
* - See: https://moz.com/blog/reddit-stumbleupon-delicious-and-hacker-news-algorithms-exposed | ||
* | ||
* @param ups Number of up votes. | ||
* @param ts Timestamp when content was created in milliseconds. | ||
*/ | ||
export function hotYCombinator (ups: number, ts: number = Date.now()) { | ||
const hoursSinceCreated = (Date.now() - ts) / (1000 * 60 * 60); | ||
return ups / Math.pow(hoursSinceCreated + 2, 1.5); | ||
} | ||
|
||
/** | ||
* Reddit's content scoring function for finding best replies regardless of time | ||
* when content was created. This function does not penalize old content. | ||
* | ||
* - See: https://medium.com/hacking-and-gonzo/how-reddit-ranking-algorithms-work-ef111e33d0d9 | ||
* | ||
* @param ups Number of up votes. | ||
* @param downs Number of down votes. | ||
*/ | ||
export function bestReddit (ups: number, downs: number) { | ||
const n = ups + downs; | ||
if (!n) return 0; | ||
const z = 1.281551565545; | ||
const p = ups / n; | ||
const left = p + 1 / (2 * n) * z * z; | ||
const right = z * Math.sqrt(p * (1 - p) / n + z * z / (4 * n * n)); | ||
const under = 1 + 1 / n * z * z; | ||
return (left - right) / under; | ||
} |
0 comments on commit
8f3351f