[Ramda] Lens in Depth
In this post, we are going to see how to use Ramda Lens.
For example, we have data:
const {log} = require('./lib/log');
const R = require('ramda');
const band = {
name: 'K.M.F.D.M',
members: {
current: [
{name: 'Sascha Konictzko', plays: ['vocals', 'synth', 'guitar', 'bass']},
{name: 'Lucia Cifarelli', plays: ['vocals', 'synth']},
{name: 'Jules Hodgson', plays: ['guitar', 'bass', 'synth']},
{name: 'Steve While', plays: ['guitar']}
],
past: [
{name: 'Raymond Watts', plays: ['vocals', 'synth']},
{name: 'En Esch', plays: ['vocals', 'drums', 'guitar', 'synth']},
{name: 'Gunter', plays: ['guitar', 'synth']}
]
}
};
R.lens:
R.lens takes a getter and a setter:
const name = R.lens(R.prop('name'), R.assoc('name'));
log(R.view(name, band)); // K.M.F.D.M
log(R.set(name, 'M.D.F.M.K', band));
R.lensProp:
There is a shorter way to do getter/setter partten:
const name = R.lensProp('name');
const makeLower = a => a.toLowerCase();
log('over lensProp: ', R.over(name, makeLower, band)); // name: "k.m.f.d.m"
log('over compose: ', R.compose(R.view(name), R.over(name, makeLower))(band)); // name: "k.m.f.d.m"
R.lensPath:
const currentMemebers = R.lensPath(['members', 'current']);
log('view path', R.view(currentMemebers, band))
We can also combine two lens together:
const name = R.lensProp('name');
const currentMemebers = R.lensPath(['members', 'current']);
//log('view path', R.view(currentMemebers, band))
const makeLower = a => a.toLowerCase();
// Use two lens together
const lowerName = R.over(name, makeLower);
const lowerMembers = R.over(currentMemebers, R.map(lowerName));
console.log('new lower name', lowerMembers(band));
R.lensIndex:
const first = R.lensIndex()
const getFistCurrentMember = R.compose(
R.view(first),
R.view(currentMemebers)
)
console.log(getFistCurrentMember(band)) // { name: 'Sascha Konictzko', plays: [ 'vocals', 'synth', 'guitar', 'bass' ] }
Actually there is a better way to do this: by using R.compose(), one thing to notice is that, when working with lens, compose should go from left to right, instead of right to left. This is because how lens works in code.
In our example:
const band = {
name: 'K.M.F.D.M',
members: {
current: [
{name: 'Sascha Konictzko', plays: ['vocals', 'synth', 'guitar', 'bass']},
{name: 'Lucia Cifarelli', plays: ['vocals', 'synth']},
{name: 'Jules Hodgson', plays: ['guitar', 'bass', 'synth']},
{name: 'Steve While', plays: ['guitar']}
],
past: [
{name: 'Raymond Watts', plays: ['vocals', 'synth']},
{name: 'En Esch', plays: ['vocals', 'drums', 'guitar', 'synth']},
{name: 'Gunter', plays: ['guitar', 'synth']}
]
}
};
We should get 'members' first then 'current' first member:
const currentMemebers = R.lensPath(['members', 'current']);
const first = R.lensIndex()
const firstCurrentMember = R.compose(
currentMemebers, first
)
console.log(R.view(firstCurrentMember, band))
You can think this is similar to Javascript Stack when using R.compose(lens1, len2).
Example:
Using the same data from previous example:
const band = {
name: 'K.M.F.D.M',
members: {
current: [
{name: 'Sascha Konictzko', plays: ['vocals', 'synth', 'guitar', 'bass']},
{name: 'Lucia Cifarelli', plays: ['vocals', 'synth']},
{name: 'Jules Hodgson', plays: ['guitar', 'bass', 'synth']},
{name: 'Steve While', plays: ['guitar']}
],
past: [
{name: 'Raymond Watts', plays: ['vocals', 'synth']},
{name: 'En Esch', plays: ['vocals', 'drums', 'guitar', 'synth']},
{name: 'Gunter', plays: ['guitar', 'synth']}
]
}
};
Requirements:
/**
* 1. Lowercase the name
* 2. Omit the plays from the past
* 3. Lowercase the current name
* 4. Create 'all' under members combine 'current' & 'past'
* 5. Pick get name and to lowercase for 'members.all'
*/
Final results should be:
/**
* {
"name": "k.m.f.d.m",
"members": {
"current": [
{
"name": "sascha konictzko",
"plays": [
"vocals",
"synth",
"guitar",
"bass"
]
},
{
"name": "lucia cifarelli",
"plays": [
"vocals",
"synth"
]
},
{
"name": "jules hodgson",
"plays": [
"guitar",
"bass",
"synth"
]
},
{
"name": "steve while",
"plays": [
"guitar"
]
}
],
"past": [
{
"name": "Raymond Watts"
},
{
"name": "En Esch"
},
{
"name": "Gunter"
}
],
"all": [
"sascha konictzko",
"lucia cifarelli",
"jules hodgson",
"steve while",
"raymond watts",
"en esch",
"gunter"
]
}
}
*/
-----
Answer:
const R = require('ramda');
const band = {
name: 'K.M.F.D.M',
members: {
current: [
{name: 'Sascha Konictzko', plays: ['vocals', 'synth', 'guitar', 'bass']},
{name: 'Lucia Cifarelli', plays: ['vocals', 'synth']},
{name: 'Jules Hodgson', plays: ['guitar', 'bass', 'synth']},
{name: 'Steve While', plays: ['guitar']}
],
past: [
{name: 'Raymond Watts', plays: ['vocals', 'synth']},
{name: 'En Esch', plays: ['vocals', 'drums', 'guitar', 'synth']},
{name: 'Gunter', plays: ['guitar', 'synth']}
]
}
};
/**
* 1. Lowercase the name
* 2. Omit the plays from the past
* 3. Lowercase the current name
*/
// makeLower :: s -> s
const makeLower = s => s.toLowerCase();
// lowerName :: obj a -> obj b
const lowerName = R.compose(makeLower, R.prop('name'));
const name = R.lensProp('name');
const pastMemebers = R.lensPath(['members', 'past']);
const currentMemebers = R.lensPath(['members', 'current']);
// Mapping over NAME lens, make string to lowercase
const lowerBandName = R.over(
name, makeLower
);
// Mapping over 'memebers.past' Lens, omit 'plays' prop
const omitPastPlays = R.over(
pastMemebers, R.map(R.omit(['plays']))
);
// Mapping over 'members.current' Lens, for each 'name' prop, make string to lowercase
const lowerCurrentMemebersName = R.over(
currentMemebers, R.map(
R.over(name, makeLower)
)
);
/**
* 4. Create 'all' under members combine 'current' & 'past'
* 5. Pick get name and to lowercase for 'members.all'
*/
const allMemebers = R.lensPath(['members', 'all']);
// lensConcat :: (Lens t, Lens s) -> a -> [b]
const lensConcat = (targetLen, srcLen) => data =>
R.over(targetLen, R.concat(R.view(srcLen, data)))(data);
// A set of tranforms over prop 'members.all'
// Set 'all' to []
// concat 'past' to 'all'
// concat 'current' to 'all'
// pick name and conver to lowercase
const createAllMembers = [
R.over(allMemebers, R.map(lowerName)),
lensConcat(allMemebers, currentMemebers),
lensConcat(allMemebers, pastMemebers),
R.set(allMemebers, [])
];
const mods = [
...createAllMembers,
lowerCurrentMemebersName,
omitPastPlays,
lowerBandName,
]
const transform = R.compose(
...mods
);
const res = transform(band);
[Ramda] Lens in Depth的更多相关文章
- [Ramda] Getter and Setter in Ramda & lens
Getter on Object: 1. prop: R.prop(}); //=> 100 R.prop('x', {}); //=> undefined 2. props: R.pro ...
- [Functional Programming] Using Lens to update nested object
For example, in React application, we have initial state; const data = { nextId: 4, todoFilter: 'SHO ...
- [React] Update Component State in React With Ramda Lenses
In this lesson, we'll refactor a React component to use Ramda lenses to update our component state. ...
- [Ramda] Change Object Properties with Ramda Lenses
In this lesson we'll learn the basics of using lenses in Ramda and see how they enable you to focus ...
- Unity3D图像后处理特效——Depth of Field 3.4
Depth of Field 3.4 is a common postprocessing effect that simulates the properties of a camera lens. ...
- [LeetCode] Minimum Depth of Binary Tree 二叉树的最小深度
Given a binary tree, find its minimum depth. The minimum depth is the number of nodes along the shor ...
- [LeetCode] Maximum Depth of Binary Tree 二叉树的最大深度
Given a binary tree, find its maximum depth. The maximum depth is the number of nodes along the long ...
- leetcode 111 minimum depth of binary tree
problem description: Given a binary tree, find its minimum depth. The minimum depth is the number of ...
- 【leetcode】Minimum Depth of Binary Tree
题目简述: Given a binary tree, find its minimum depth. The minimum depth is the number of nodes along th ...
随机推荐
- vue 中如何对公共css、 js 方法进行单文件统一管理,全局调用
1.前言 最近,为公司开发交付的一个后台管理系统项目,我使用了 Vue 框架进行开发实践. 模块化.组件化.工程化的开发体验非常好.良好的 api,优雅的设计,对于工程师非常友好. 但是由于模块比较多 ...
- Tomcat中文乱码解决办法
有时候发现自己将中文编码后还是会存在乱码的情况,解决办法就是在Server.xml中的Connector结点,配置 URIEncoding="UTF-8"即可
- Debian 9 VIM 使用鼠标右键复制
起因 装了 debian 9 以后,vim没有办法使用鼠标直接选择并复制,后来发现是默认的配置问题.于是需要按照以下方式解决: 解决方法 1. 编辑 vim 的默认配置文件 vim /usr/shar ...
- git命令详解( 七 )
此为git命令详解的第七篇 这章我们可以来逐渐揭开 git push.fetch 和 pull 的神秘面纱了.我们会逐个介绍这几个命令,它们在理念上是非常相似的. git push的参数 git ...
- Java网络编程案例---聊天室
网络编程是指编写运行在多个设备(计算机)的程序,这些设备都通过网络连接起来. java.net包中JavaSE的API包含有类和接口,它们提供低层次的通信细节.你可以直接使用这些类和接口,来专注于解决 ...
- ubantu 执行sudo apt-get update 出现校验不符问题
一直被这个问题困扰,今天安装mongodb时,看了别人博客暂时解决了,不知道会不会出什么问题. 直接打开软件更新器: 然后点击其他软件,去掉两个独立的多选项: 再执行一遍 sudo apt-get u ...
- VMware5.5-存储
存储 存储类型 VMFS(vmvare公司提供) NFS 本地存储 添加主机硬盘 扩展现有的磁盘或者添加新的硬盘 添加完成后点击全部重新扫描 添加存储器. 网络存储 网络存储的运用大大提高了虚机话的便 ...
- 3.27模拟赛 sutoringu(后缀数组)
\(\color{white}{mjt是机房模拟赛独自切过题的唯一的人...}\) (应本人要求删掉惹) \(Description\) 给你\(n,k\)和长为\(n\)的字符串\(s\).一个区间 ...
- 牛客国庆集训派对Day1.B.Attack on Titan(思路 最短路Dijkstra)
题目链接 \(Description\) 给定\(n,m,C\)及大小为\((n+1)(m+1)\)的矩阵\(c[i][j]\).平面上有\((n+1)(m+1)\)个点,从\((0,0)\)编号到\ ...
- Yahoo Programming Contest 2019.E.Odd Subrectangles(思路 线性基)
题目链接 \(Description\) 给定一个\(n\times m\)的\(01\)矩阵.求任意选出\(r\)行.\(c\)列(共\(2^{n+m}\)种方案),使得这\(r\)行\(c\)列的 ...