如何使用数组项预加载 Ramda curried 函数?
How to preload a Ramda curried function with item of an Array?
我有 tagsList
,它有大约 20 个标签,termIds
是最多 3 个标签 ID 的数组。
我试图在 tagsList 中找到与 termIds 中的 id 相匹配的标签,然后设置它们的边框。希望避免 for 循环和面向对象编程,转而使用 Ramda curry.
的函数式编程解决方案
tagsList 中的标签如下所示:
{
term: 'hi',
id: 123
}
termId 可能看起来像 [123, 345, 678]
当我找到匹配的 ID 时,我会为该标签提供一个新密钥 border1:true
、border2:true
等...
目标:
有一个标签列表,我有另一个 termId 数组,目标是查看 tagsList 中的任何标签是否具有与 termId 匹配的 ID。如果给它一个border1,如果有2个,那么第2个得到border2,最后3个得到border 3.
我首先尝试的是:
const checkId = _.curry((term_id, tag) => {
if (tag.id === term_id) {
console.log('match found!', tag)
}
});
const matchId = checkId(termIds);
const coloredTags = R.map(matchId, tagsList);
console.log('coloredTags', coloredTags)
return tagsList;
但是这不起作用,因为我将整个 termIds 数组预加载到 checkId
函数中。相反,我想用单个项目预加载它。
接下来,我尝试了这个我认为可行的方法,但出现了一个奇怪的错误:
const matchId = R.forEach(checkId, termIds);
啊,刚刚弄明白了,我不得不第二次柯里化逻辑:
const matchId = R.curry((tag, term_id) => {
if (tag.id === Number(term_id)) {
console.log('match found!', tag)
}
});
const curried = R.curry((termIds, tag) => {
return R.map(matchId(tag), termIds);
});
const coloredTags = R.map(curried(termIds), tagsList);
console.log('coloredTags', coloredTags)
return tagsList;
所以在 coloredTags
行,来自 tagsLists 的标签进入 curried(termIds)。 Ramda 函数从右到左接受参数。
curried(termIds)
已经预加载了 termIds 数组。所以接下来在 const curried =
行中,termIds 数组和单个标签进入,标签被发送到下一个柯里化函数 matchId
,termIds
数组也被放置在 R.map
。 Ramda 列表函数接受数据数组作为正确的参数。
终于在 matchId
我可以检查了!
更新
所以上面回答了我问的问题,关于如何咖喱数组中的项目。但是,它在我的应用程序中导致了一个错误。由于 termIds
数组最多可容纳 3 个项目,因此 coloredTags R.map
将 运行 最多 3 次并在我的标签列表中创建重复标签。
为了完整起见,这就是我解决问题的方法,更简单,不需要使用双重柯里化函数。
const setTagColors = (tagsList, state) => {
const setBorder = (tag) => {
if (tag.id === Number(state.term_id_1)) {
tag.border1 = true;
} else if (tag.id === Number(state.term_id_2)) {
tag.border2 = true;
} else if (tag.id === Number(state.term_id_3)) {
tag.border3 = true;
}
return tag;
};
const coloredTags = R.map(setBorder, tagsList);
return state.term_id_1 ? coloredTags : tagsList;
};
我觉得没有Ramda,纯JS就够了。你只需要一张地图:
var tagsList = [{term: 'hi', id: 123}, {term: 'ho', id: 152}, {term: 'hu', id: 345}, {term: 'ha', id: 72}];
var termIds = [123, 345, 678];
var i = 1;
var results = tagsList.map(x => {
if (termIds.indexOf(x.id) !== -1) x["border"+ (i++)] = true;
return x;
});
console.log(results);
这似乎是一个合理的方法:
R.map(tag => {
const index = R.indexOf(tag.id, termIds);
return (index > -1) ? R.assoc('border' + (index + 1), true, tag) : tag
})(tagsList);
//=> [
// {id: 123, term: "hi", border1: true},
// {id: 152, term: "ho"},
// {id: 345, term: "hu", border2: true},
// {id: 72, term: "ha"}
// ]
虽然如果付出足够的努力,它可能会变得不加分,但它的可读性可能会差很多。
您可以在 Ramda REPL.
上看到实际效果
如果你想把它变成一个可重用的函数,你可以这样做:
const addBorders = R.curry((terms, tags) => R.map(tag => {
const index = R.indexOf(tag.id, terms);
return (index > -1) ? R.assoc('border' + (index + 1), true, tag) : tag
})(tags))
addBorders(termIds, tagsList)
(调用 curry
是 Ramda 的习惯。这意味着你可以调用 addBorders(termIds)
并取回一个正在寻找标签的可重用函数。如果你不需要那个,你可以跳过 curry
包装器。)
这个版本也在Ramda REPL.
我有 tagsList
,它有大约 20 个标签,termIds
是最多 3 个标签 ID 的数组。
我试图在 tagsList 中找到与 termIds 中的 id 相匹配的标签,然后设置它们的边框。希望避免 for 循环和面向对象编程,转而使用 Ramda curry.
的函数式编程解决方案tagsList 中的标签如下所示:
{
term: 'hi',
id: 123
}
termId 可能看起来像 [123, 345, 678]
当我找到匹配的 ID 时,我会为该标签提供一个新密钥 border1:true
、border2:true
等...
目标:
有一个标签列表,我有另一个 termId 数组,目标是查看 tagsList 中的任何标签是否具有与 termId 匹配的 ID。如果给它一个border1,如果有2个,那么第2个得到border2,最后3个得到border 3.
我首先尝试的是:
const checkId = _.curry((term_id, tag) => {
if (tag.id === term_id) {
console.log('match found!', tag)
}
});
const matchId = checkId(termIds);
const coloredTags = R.map(matchId, tagsList);
console.log('coloredTags', coloredTags)
return tagsList;
但是这不起作用,因为我将整个 termIds 数组预加载到 checkId
函数中。相反,我想用单个项目预加载它。
接下来,我尝试了这个我认为可行的方法,但出现了一个奇怪的错误:
const matchId = R.forEach(checkId, termIds);
啊,刚刚弄明白了,我不得不第二次柯里化逻辑:
const matchId = R.curry((tag, term_id) => {
if (tag.id === Number(term_id)) {
console.log('match found!', tag)
}
});
const curried = R.curry((termIds, tag) => {
return R.map(matchId(tag), termIds);
});
const coloredTags = R.map(curried(termIds), tagsList);
console.log('coloredTags', coloredTags)
return tagsList;
所以在 coloredTags
行,来自 tagsLists 的标签进入 curried(termIds)。 Ramda 函数从右到左接受参数。
curried(termIds)
已经预加载了 termIds 数组。所以接下来在 const curried =
行中,termIds 数组和单个标签进入,标签被发送到下一个柯里化函数 matchId
,termIds
数组也被放置在 R.map
。 Ramda 列表函数接受数据数组作为正确的参数。
终于在 matchId
我可以检查了!
更新
所以上面回答了我问的问题,关于如何咖喱数组中的项目。但是,它在我的应用程序中导致了一个错误。由于 termIds
数组最多可容纳 3 个项目,因此 coloredTags R.map
将 运行 最多 3 次并在我的标签列表中创建重复标签。
为了完整起见,这就是我解决问题的方法,更简单,不需要使用双重柯里化函数。
const setTagColors = (tagsList, state) => {
const setBorder = (tag) => {
if (tag.id === Number(state.term_id_1)) {
tag.border1 = true;
} else if (tag.id === Number(state.term_id_2)) {
tag.border2 = true;
} else if (tag.id === Number(state.term_id_3)) {
tag.border3 = true;
}
return tag;
};
const coloredTags = R.map(setBorder, tagsList);
return state.term_id_1 ? coloredTags : tagsList;
};
我觉得没有Ramda,纯JS就够了。你只需要一张地图:
var tagsList = [{term: 'hi', id: 123}, {term: 'ho', id: 152}, {term: 'hu', id: 345}, {term: 'ha', id: 72}];
var termIds = [123, 345, 678];
var i = 1;
var results = tagsList.map(x => {
if (termIds.indexOf(x.id) !== -1) x["border"+ (i++)] = true;
return x;
});
console.log(results);
这似乎是一个合理的方法:
R.map(tag => {
const index = R.indexOf(tag.id, termIds);
return (index > -1) ? R.assoc('border' + (index + 1), true, tag) : tag
})(tagsList);
//=> [
// {id: 123, term: "hi", border1: true},
// {id: 152, term: "ho"},
// {id: 345, term: "hu", border2: true},
// {id: 72, term: "ha"}
// ]
虽然如果付出足够的努力,它可能会变得不加分,但它的可读性可能会差很多。
您可以在 Ramda REPL.
上看到实际效果如果你想把它变成一个可重用的函数,你可以这样做:
const addBorders = R.curry((terms, tags) => R.map(tag => {
const index = R.indexOf(tag.id, terms);
return (index > -1) ? R.assoc('border' + (index + 1), true, tag) : tag
})(tags))
addBorders(termIds, tagsList)
(调用 curry
是 Ramda 的习惯。这意味着你可以调用 addBorders(termIds)
并取回一个正在寻找标签的可重用函数。如果你不需要那个,你可以跳过 curry
包装器。)
这个版本也在Ramda REPL.