[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 ...
随机推荐
- 元素滚动到底部或顶部时阻止body滚动
移动端的弹窗内容有滚动条,滚动到底部或顶部时或影响弹窗下的body滚动,某些浏览器滚动到顶部时不松手就触发了刷新页面的情况,如果不需要这样的默认体验,就需要加一下判断了. var startX,sta ...
- BZOJ3772 精神污染 主席树 dfs序
欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - BZOJ3772 题意概括 给出一个树,共n个节点. 有m条互不相同的树上路径. 现在让你随机选择2条路径,问 ...
- linux系统虚拟机下安装nginx基础
虽然安装nginx什么的 .以及如何配置等等一系列的资料案例已经很多了 但是作为菜鸟的我还是搞了半天哈 官网上面也有.但是一些细节方面的并没有说明.导致踩了半天坑才搞好 本案例的系统环境 wi ...
- day65 request对象,以及方法,response对象,render,redirect
这里的都是我们会频繁使用到的,用得多了自然就会了,我们写项目都是少不了这些用法的,所以这就把老师的博客粘过来就好了, Request对象 官方文档 属性 所有的属性应该被认为是只读的,除非另有说明. ...
- 总结几种清除浏览器的缓存,适用于明明已经修改bug,但是测试人员说问题还存在的情况下
1.meta方法<METAHTTP-EQUIV="pragma"CONTENT="no-cache"><METAHTTP-EQUIV=&quo ...
- HDU-2177 取(2堆)石子游戏 (威佐夫博奕)
Problem Description 有两堆石子,数量任意,可以不同.游戏开始由两个人轮流取石子.游戏规定,每次有两种不同的取法,一是可以在任意的一堆中取走任意多的石子:二是可以在两堆中同时取走相同 ...
- POJ 3189 Steady Cow Assignment 【二分】+【多重匹配】
<题目链接> 题目大意: 有n头牛,m个牛棚,每个牛棚都有一定的容量(就是最多能装多少只牛),然后每只牛对每个牛棚的喜好度不同(就是所有牛圈在每个牛心中都有一个排名),然后要求所有的牛都进 ...
- P2659 美丽的序列
P2659 美丽的序列对于当前的最小值,找到最大的左右边界,然后更新答案.用单调队列确定左右边界,O(n)做法. #include<iostream> #include<cstdio ...
- 用户不在sudoers文件中,此事将被报告
在给Virtual Box搭配共享文件夹后,普通用户使用sudo时,报错XX不在sudoers文件中.此事将被报告 然后我就按照网上教程,不巧的是正好用错误的教程修改了sudoers文件,造成root ...
- 大数据环境完全分布式搭建hbase-0.96.2-hadoop2
1.上传hbase安装包 2.解压 3.配置hbase集群,要修改3个文件 (首先zookeeper集群已经安装好了 并且启动 hadoop启动) 注意:要把hadoop的hdfs-site.xml和 ...