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的更多相关文章

  1. [Ramda] Getter and Setter in Ramda & lens

    Getter on Object: 1. prop: R.prop(}); //=> 100 R.prop('x', {}); //=> undefined 2. props: R.pro ...

  2. [Functional Programming] Using Lens to update nested object

    For example, in React application, we have initial state; const data = { nextId: 4, todoFilter: 'SHO ...

  3. [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. ...

  4. [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 ...

  5. Unity3D图像后处理特效——Depth of Field 3.4

    Depth of Field 3.4 is a common postprocessing effect that simulates the properties of a camera lens. ...

  6. [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 ...

  7. [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 ...

  8. leetcode 111 minimum depth of binary tree

    problem description: Given a binary tree, find its minimum depth. The minimum depth is the number of ...

  9. 【leetcode】Minimum Depth of Binary Tree

    题目简述: Given a binary tree, find its minimum depth. The minimum depth is the number of nodes along th ...

随机推荐

  1. nssm部署.net core console到windows服务

    轻便式发布 与.net fx不同 需要dotnet.exe来引导 Path:默认为 C:\Program Files\dotnet\dotnet.exe: Startup directory:程序所在 ...

  2. execution(* com.sample.service.impl..*.*(..))

    execution(* com.sample.service.impl..*.*(..)) 解释如下: 符号 含义 execution() 表达式的主体: 第一个”*“符号 表示返回值的类型任意: c ...

  3. oracle左连接连表查询

    要想把该表的数据全部查出来,必须select中出现该表的字段. SELECT distinct a.ZGSWSKFJ_DM,b.ZGSWJ_DM,b.SSGLY_DM,b.NSRSBH,b.NSRMC ...

  4. Python库: PrettyTable 模块

    一,PrettyTable简介 PrettyTable是python中的一个第三方库,可用来生成美观的ASCII格式的表格: 二,PrettyTable安装 使用PIP即可十分方便的安装PrettyT ...

  5. continue — Skip to the next iteration of a loop in a shell script

    continue — Skip to the next iteration of a loop in a shell script

  6. Linux学习笔记7

    执行脚本篇章 r w x 读  写 执行 4 2 1 如果要启动tomcat 服务器 即执行 startup.sh脚本文件 1> #chmod 444 startup.sh 增加文本读权限 -r ...

  7. EF Core中的多对多映射如何实现?

    EF 6.X中的多对多映射是直接使用HasMany-HasMany来做的.但是到了EF Core中,不再直接支持这种方式了,可以是可以使用,但是不推荐,具体使用可以参考<你必须掌握的Entity ...

  8. MySQL 一对多查询

    group_concat简单来说,这个函数的作用就是连接多个字段 数据表首先我们先建立两个表 CREATE TABLE `student` ( `id` ) NOT NULL AUTO_INCREME ...

  9. C# virtual、abstract

    (1) virtual:修饰的方法必须有实现 abstract:修饰的方法一定不能实现 (2) virtual:可被子类重写, 子类中必须用overide修饰 abstract:必须被子类重写 (3) ...

  10. React Native升级目标SDK

    React Native升级目标SDK 打开在 android/app/的build.gradle 找到 android { } 区块 改变以下属性 compileSdkVersion 26 buil ...