使用 Ramda 将字段添加到数组中最后出现的对象的最佳方法是什么?
Whats the best way to add a field to the last occurrence object in an array with Ramda?
假设我有一个简单的对象数组,它们都有一个类型字段:
let arr = [
{
"name": "First",
"type": "test"
},
{
"name": "Second",
"type": "test"
},
{
"name": "Third",
"type": "test2"
},
{
"name": "Fourth",
"type": "test2"
},
{
"name": "Fifth",
"type": "test3"
},
{
"name": "Sixth",
"type": "test3"
}
]
使用 Ramda 将字段添加到每个类型的最后一次出现的最佳方法是什么?
获得:
let newArr = [
{
"name": "First",
"type": "test"
},
{
"name": "Second",
"type": "test",
"last": true
},
{
"name": "Third",
"type": "test2"
},
{
"name": "Fourth",
"type": "test2",
"last": true
},
{
"name": "Fifth",
"type": "test3"
},
{
"name": "Sixth",
"type": "test3",
"last": true
}
]
我实在想不通!提前致谢! :)
这是一种可能的解决方案:
// f :: [{ type :: a }] -> [{ type :: a, last :: Boolean }]
const f = R.addIndex(R.map)((x, idx, xs) =>
R.assoc('last',
R.none(R.propEq('type', x.type), R.drop(idx + 1, xs)),
x));
对于列表中的每个值,我们向前看是否有相同的后续值 type
属性.
我猜测您的数据已按显示分组,并且不同类型的元素没有散布。如果那个猜测是错误的,就需要一个不同的解决方案。
我的版本涉及两个辅助函数,其中一个根据谓词对列表进行分组,该谓词报告两个(连续的)值是否属于一起:
const breakWhen = R.curry(
(pred, list) => R.addIndex(R.reduce)((acc, el, idx, els) => {
if (idx === 0 || !pred(els[idx - 1], el)) {
acc.push([el])
} else {
acc[acc.length - 1].push(el);
}
return acc;
}, [], list)
);
第二个 Lens
关注列表的最后一个元素:
const lastLens = R.lens(R.last, (a, s) => R.update(s.length - 1, a, s));
有了这两个,你可以构建这样一个函数:
const checkLasts = R.pipe(
breakWhen(R.eqProps('type')),
R.map(R.over(lastLens, R.assoc('last', true))),
R.flatten
);
checkLasts(arr);
breakWhen
的实现非常糟糕。我确定有更好的东西。该函数结合了 Ramda 的 splitEvery
and splitWhen
的想法
这与 David Chambers 的解决方案略有不同,因为它没有向剩余元素添加 last: false
属性。但显然它更复杂。如果数据没有按预期分组,它们中的任何一个都会失败。
假设我有一个简单的对象数组,它们都有一个类型字段:
let arr = [
{
"name": "First",
"type": "test"
},
{
"name": "Second",
"type": "test"
},
{
"name": "Third",
"type": "test2"
},
{
"name": "Fourth",
"type": "test2"
},
{
"name": "Fifth",
"type": "test3"
},
{
"name": "Sixth",
"type": "test3"
}
]
使用 Ramda 将字段添加到每个类型的最后一次出现的最佳方法是什么?
获得:
let newArr = [
{
"name": "First",
"type": "test"
},
{
"name": "Second",
"type": "test",
"last": true
},
{
"name": "Third",
"type": "test2"
},
{
"name": "Fourth",
"type": "test2",
"last": true
},
{
"name": "Fifth",
"type": "test3"
},
{
"name": "Sixth",
"type": "test3",
"last": true
}
]
我实在想不通!提前致谢! :)
这是一种可能的解决方案:
// f :: [{ type :: a }] -> [{ type :: a, last :: Boolean }]
const f = R.addIndex(R.map)((x, idx, xs) =>
R.assoc('last',
R.none(R.propEq('type', x.type), R.drop(idx + 1, xs)),
x));
对于列表中的每个值,我们向前看是否有相同的后续值 type
属性.
我猜测您的数据已按显示分组,并且不同类型的元素没有散布。如果那个猜测是错误的,就需要一个不同的解决方案。
我的版本涉及两个辅助函数,其中一个根据谓词对列表进行分组,该谓词报告两个(连续的)值是否属于一起:
const breakWhen = R.curry(
(pred, list) => R.addIndex(R.reduce)((acc, el, idx, els) => {
if (idx === 0 || !pred(els[idx - 1], el)) {
acc.push([el])
} else {
acc[acc.length - 1].push(el);
}
return acc;
}, [], list)
);
第二个 Lens
关注列表的最后一个元素:
const lastLens = R.lens(R.last, (a, s) => R.update(s.length - 1, a, s));
有了这两个,你可以构建这样一个函数:
const checkLasts = R.pipe(
breakWhen(R.eqProps('type')),
R.map(R.over(lastLens, R.assoc('last', true))),
R.flatten
);
checkLasts(arr);
breakWhen
的实现非常糟糕。我确定有更好的东西。该函数结合了 Ramda 的 splitEvery
and splitWhen
这与 David Chambers 的解决方案略有不同,因为它没有向剩余元素添加 last: false
属性。但显然它更复杂。如果数据没有按预期分组,它们中的任何一个都会失败。