分享web开发知识

注册/登录|最近发布|今日推荐

主页 IT知识网页技术软件开发前端开发代码编程运营维护技术分享教程案例
当前位置:首页 > 软件开发

[Transducer + Ramda] Write highly performance / functional code by using transducer-js and ramda.js libs

发布时间:2023-09-06 01:36责任编辑:胡小海关键词:js

Tansducer-js lib

A high performance Transducers implementation for JavaScript.

Transducers are composable algorithmic transformations. They are independent from the context of their input and output sources and specify only the essence of the transformation in terms of an individual element. Because transducers are decoupled from input or output sources, they can be used in many different processes - collections, streams, channels, observables, etc. Transducers compose directly, without awareness of input or creation of intermediate aggregates.

The whole point to use transducer-js lib is because in normal FP approach, when se do:

Array ???.map ???.filter ???.reducer

We actually loop though the array 3 times. So time complexity is O(n). If you can reduce 3 times into single time. And reduce the time complexity from O(n) to O(1). It would be a huge proferemce improvement for large datasets.

Second, normal approach we are limiting ourself with Array type, we cannot call ‘mpa, filter, reduce‘ on type of Object, Map and Set. But with transducer-js, we are able to do that as well.

Ramda.js:

The primary distinguishing features of Ramda are:

  • Ramda emphasizes a purer functional style. Immutability and side-effect free functions are at the heart of its design philosophy. This can help you get the job done with simple, elegant code.

  • Ramda functions are automatically curried. This allows you to easily build up new functions from old ones simply by not supplying the final parameters.

  • The parameters to Ramda functions are arranged to make it convenient for currying. The data to be operated on is generally supplied last.

The last two points together make it very easy to build functions as sequences of simpler functions, each of which transforms the data and passes it along to the next. Ramda is designed to support this style of coding.

The whole point we are using Ramda.js is because it enforce the FP approach, and auto currying is a huge win in FP style. Also you can use loadsh/fp if you wish.

Now let‘s see what kind of problem we want to solve:

lets say we have two string:

`hostname, username `
` ???10.1.10.1, zwan ???10.1.11.1, wan`

And we want to apply so transform function to those string and the final output should be:

[ { hostname: ‘10.1.10.1‘, username: ‘zwan‘ }, ?{ hostname: ‘10.1.11.1‘, username: ‘wan‘ } ]

Now here is one of the possible solution by only using ramda.js:

var R = require("ramda");const headerStr = `hostname, username `;const contentStr = ` ???10.1.10.1, zwan ???10.1.11.1, wan`;/** * Working with Ramda.js */const stringToArray = R.compose( ???R.map(R.trim), ???R.filter(Boolean), ???R.split(‘,‘));const transformContent = R.compose( ???R.map(stringToArray), ???R.filter(Boolean), ???R.split(‘\n‘));const keyValPair = R.useWith( ???R.map, ???[ ???????R.zipObj, ???????R.identity ???]);const header = stringToArray(headerStr);const content = transformContent(contentStr);const res = keyValPair(header, content);console.log(res);

The solution is fine, it should be really easy to be tested and maintained. We also able to compose the logic such as :

const stringToArray = R.compose( ???R.map(R.trim), ???R.filter(Boolean), ???R.split(‘,‘));const transformContent = R.compose( ???R.map(stringToArray), ???R.filter(Boolean), ???R.split(‘\n‘));

The only problem (from my point of view) is the preformence. 

When we call ‘R.map, R.filter‘, it actually loop though the array twice. When we call ‘R.map(stringToArray)‘, the nested loop might increase the time complxity to O(n ^2).

Here is the transducer-js comes to help.

var t = require("transducers-js");var R = require("ramda");const headerStr = `hostname, username `;const contentStr = ` ???10.1.10.1, zwan ???10.1.11.1, wan`;/** * Working with transducer-js + Rmada.js */const stringToArr = R.compose( ???t.comp( ???????t.map(R.trim), ???????t.filter(R.isNil) ???), ???R.split(‘,‘));const transformCnt = R.compose( ???t.comp( ???????t.map(stringToArr), ???????t.filter(R.isNil) ???), ???R.split(‘\n‘));const keyValPair = R.useWith( ???R.map, ???[ ???????R.zipObj, ???????R.identity ???]);const h = stringToArr(headerStr);const c = transformCnt(contentStr);const res2 = keyValPair(h, c);console.log("res2", res);

As you can see that, we replace

// fromconst stringToArray = R.compose( ???R.map(R.trim), ???R.filter(Boolean), ???R.split(‘,‘));// toconst stringToArr = R.compose( ???t.comp( ???????t.map(R.trim), ???????t.filter(R.isNil) ???), ???R.split(‘,‘));

From ‘R.map, R.filter‘, loop twice to ‘t.comp(t.map, t.filter)‘ only loop once. ‘t.comp‘ helps to compose two transform opreation together. If you think further, this is not that easy task to combine filter‘s prediction function with map‘s transform function:

filter prediction:

f => (a → Boolean)

map transform:

f => (a → b)

Because the return type is not the same, so they cannot compose naturally. transducer-js helps us to make it easily.

[Transducer + Ramda] Write highly performance / functional code by using transducer-js and ramda.js libs

原文地址:https://www.cnblogs.com/Answer1215/p/8290066.html

知识推荐

我的编程学习网——分享web前端后端开发技术知识。 垃圾信息处理邮箱 tousu563@163.com 网站地图
icp备案号 闽ICP备2023006418号-8 不良信息举报平台 互联网安全管理备案 Copyright 2023 www.wodecom.cn All Rights Reserved