Javascript Functional Programming

Functional Programming

  • Less Bug/Code
    • Composable High order function(filter、map、reduce)
    • Functions are values
    • function inside a function, we call callback(stack)
  • Map
    • Arrow Function can write less code. It means less bug
      • you can remove function & return keyword when using arrow function
      • if you have multiple operations in our reduce function need return keyword
    • map function just like filter function and it takes callback function as parameter
  • Reduce
    • can do anything like find, map or filter do
    • the difference between map and reduce is that it need initial value behind the function
    • the second parameter must be value, can not be variable

CSV to json format(Using NodeJS)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
var fs = require('fs');
var output = fs.readFileSync('data/data.txt', 'utf8')
.trim()
.split("\n")
.map((row) => row.split(','))
.reduce((customers,row)=>{
// 如果沒有值就用空的當預設值,之後push才不會有問題
customers[row[0]] = customers[row[0]] || [];
customers[row[0]].push({
'product':row[1],
'price':row[2],
'amount':row[3]
});
return customers;
}, {});

console.log('output',JSON.stringify(output, null, 2));

1
2
3
4
5
6
mark johansson,waffle iron,80,2
mark johansson,blender,200,1
mark johansson,knife,10,4
Nikita Smith,waffle iron,80,1
Nikita Smith,knife,10,2
Nikita Smith,pot,20,3

recursive

- maxium call of stack
- es5 having the maxium call of stack limitation, but es6 removed this limitation by using bubble simulation
    -  tail call optimization.
1
2
3
4
5
6
7
8
9
10
11
var getMenuTree = (category, parent) => {
let nodeResult = {};
category
.filter((c) => c.parent_id == parent)
.forEach((c) => nodeResult[c.id] = getMenuTree(category, c.id));
return nodeResult;
};
var categories = JSON.parse(fs.readFileSync('data/menutree.json', 'utf8'));

//'hello',categories,
console.log(JSON.stringify(getMenuTree(categories, null), null, 2));
1
[{"id":"animals","parent_id":null},{"id":"mammals","parent_id":"animals"},{"id":"cats","parent_id":"mammals"},{"id":"dogs","parent_id":"mammals"},{"id":"chihuahua","parent_id":"dogs"},{"id":"labrador","parent_id":"dogs"},{"id":"persian","parent_id":"cats"},{"id":"siamese","parent_id":"cats"}]

FuncDoor

  • Using FuncDoor
    • need passing one string parameter and one function parameter
    • they will map together when be called
    • pass each value to each function and return the new structures
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
var fs = require('fs');

var reduceCustomer = (output) => output.reduce((output,row)=>{
// 如果沒有值就用空的當預設值,之後push才不會有問題
output[row[0]] = output[row[0]] || [];
output[row[0]].push({
'product':row[1],
'price':row[2],
'amount':row[3]
});
return output;
}, {});

var funcDoor = (path, fn) => {
var rawData = (path) => fs.readFileSync(path, 'utf8')
.trim()
.split("\n");
// 要傳入參數,否則最後的結果還是function
var result = (path)=>fn(rawData(path).map((row) => {
return row.split(',')
} ));
return result(path);
}


console.log( funcDoor('data/data.txt', reduceCustomer));
// return;
// console.log('output',JSON.stringify(convertJson('data/data.txt'), null, 2));

var reduceCsv = (output) => output.reduce((output, row) => {
// 直接整理到一個result的key,之後就不用煩惱怎麼把key移掉
output['result'] = output['result']||[];
let input = {
'id':row[0],
'parent_id':row[1]!='null' ? row[1] : JSON.parse(row[1])
};
output['result'].push(input);
// output[i] = input;
return output
} ,{})['result']
let menuTreeResult;
console.log(menuTreeResult = funcDoor('data/menutree.txt', reduceCsv));
fs.writeFile('./data/menutree.json',JSON.stringify(menuTreeResult, null ,2));