1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
|
#!/usr/bin/env node
'use strict';
// Procedural, with manual accumulator
function task1a ( ns ) {
let ret = 0;
for ( const [i, left] of ns.entries() )
for ( const right of ns.slice(i+1) )
if ( left > (right * 2) )
ret++;
return ret;
}
// task1a, with inner loop (for&if) refactored to functional (filter&length).
function task1b ( ns ) {
let ret = 0;
for ( const [i, left] of ns.entries() ) {
ret += ns.slice(i+1).filter((right) => left > (right * 2)).length;
}
return ret;
}
// task1b, with the filter expression extracted to a named local function.
function task1c ( ns ) {
let ret = 0;
for ( const [i, left] of ns.entries() ) {
const is_reverse_pair = (right) => left > (right * 2);
ret += ns.slice(i+1)
.filter(is_reverse_pair)
.length;
}
return ret;
}
// task1c, with the outer loop refactored to .map(), and accumulator embedded in a .reduce().
function task1d ( ns ) {
const add = (a, b) => a + b;
const count_of_reverse_pairs_with_left = ([i, left]) => {
const is_reverse_pair = (right) => left > (right * 2);
return ns.slice(i+1)
.filter(is_reverse_pair)
.length;
}
return [...ns.entries()].map( count_of_reverse_pairs_with_left ).reduce(add, 0);
}
// Cannot use a faster .reduce directly on Iterator; experimental feature provided by Node.
function task1e ( ns ) {
const count_of_reverse_pairs_with_this_element = (accumumlator, [i, left]) => {
const is_reverse_pair = (right) => left > (right * 2);
const count = ns.slice(i+1)
.filter(is_reverse_pair)
.length;
return accumumlator + count;
}
return [ ...ns.entries() ].reduce(count_of_reverse_pairs_with_this_element, 0);
}
// task1d with map+reduce merged
function task1f ( ns ) {
// const add = (a, b) => a + b;
const reverse_pairs = ([i, left]) => {
const is_reverse_pair = (right) => left > (right * 2);
return ns.slice(i+1)
.filter(is_reverse_pair)
.length;
}
const sum_reverse_pairs = (a, e) => a + reverse_pairs(e);
return [ ...ns.entries() ].reduce(sum_reverse_pairs, 0);
}
// pre-doubled once into a parallel `two_n` array, to reduce recalculations.
function task1g ( ns ) {
const two_n = ns.map( n => 2*n );
const reverse_pairs = ([i, left]) => {
const is_reverse_pair = (right) => left > right;
return two_n.slice(i+1)
.filter(is_reverse_pair)
.length;
}
const sum_reverse_pairs = (a, e) => a + reverse_pairs(e);
return [ ...ns.entries() ].reduce(sum_reverse_pairs, 0);
}
// Extracted "combinations"
function task1h ( ns ) {
const combinations_2 = (arr, func) => {
arr.forEach( (left,i) => {
arr.slice(i+1).map( (right) => func(left, right) );
});
}
let count = 0;
const count_wanted = (L,R) => { if ( L > (R * 2) ) count++ };
combinations_2(ns, count_wanted);
return count;
}
const subs = [
[ 'task1a', task1a ],
[ 'task1b', task1b ],
[ 'task1c', task1c ],
[ 'task1d', task1d ],
[ 'task1e', task1e ],
[ 'task1f', task1f ],
[ 'task1g', task1g ],
[ 'task1h', task1h ],
];
const tests = [
[ 2, [1, 3, 2, 3, 1], 'Example 1 from task' ],
[ 3, [2, 4, 3, 5, 1], 'Example 2 from task' ],
[ 0, [] , 'Null array' ],
];
let test_number = 0;
function is ( got, expected, desc ) {
test_number++;
const ok_msg = (got === expected) ? "ok" : "not ok";
const description = (typeof desc !== 'undefined') ? ` - ${desc}` : '';
console.log(`${ok_msg} ${test_number}${description}`);
}
for ( const [ sub_name, task1_coderef ] of subs ) {
for ( const [ expected, input, test_name ] of tests ) {
const got = task1_coderef(input);
is( got, expected, `${sub_name}: ${test_name}`);
}
}
|