如何使用数组项预加载Ramda curried函数?

时间:2016-12-25 04:00:30

标签: javascript arrays functional-programming ramda.js

我的tagsList有大约20个标签,而termIds是最多3个标签ID的数组。

我正在尝试在tagsList中找到与termIds中的id匹配的标记,然后设置它们的边框。希望使用Ramda curry来避免使用循环和面向对象的编程,而使用函数式编程解决方案。

tagsList中的标记如下所示:

{
    term: 'hi',
    id: 123
}

termIds可能看起来像[123, 345, 678]

当我找到匹配的ID时,我会为该标记添加新密钥border1:trueborder2:true等...

目标:

有一个标签列表,我有另一个termIds数组,目标是查看tagsList中的任何标签是否具有与termIds匹配的id。如果是这样,给它一个border1,如果有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);

enter image description here

3 个答案:

答案 0 :(得分:1)

我认为纯粹的JS足以在没有Ramda的情况下完成。你只需要一张地图:



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);




答案 1 :(得分:1)

这似乎是一种合理的方法:

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

答案 2 :(得分:-1)

啊只是想通了,我不得不第二次讨论这个逻辑:

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数组和单个标记使其进入并且标记被发送到下一个curried函数matchIdtermIds数组也放在R.map数组中{1}}。 Ramda列表函数接受数据数组作为右边的参数。

最后在matchId我可以进行检查!

enter image description here

<强>更新

所以上面回答了我问的问题,关于如何从数组中剔除一个项目。但是它导致了我的应用程序中的错误。由于termIds数组最多可包含3个项目,因此coloredTags R.map最多可运行3次,并在我的tagsList中创建重复的标记。

所以只是为了完整性,这就是我解决问题的方法,更简单,并且不需要使用双重curried函数。

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;
};