我们正在尝试利用Ramda来避免一些暴力编程。我们有一个对象数组,如下所示:
[
{id: "001", failedReason: [1000]},
{id: "001", failedReason: [1001]},
{id: "001", failedReason: [1002]},
{id: "001", failedReason: [1000]},
{id: "001", failedReason: [1000, 1003]},
{id: "002", failedReason: [1000]}
]
我们希望对其进行转换,使其看起来像这样:
[
{id: "001", failedReason: [1000, 1001, 1002, 1003]},
{id: "002", failedReason: [1000]}
]
基本上它会根据id减少数组,并累积一个包含该id的所有“failedReasons”的子“failedReason”数组。我们希望一些Ramda魔术可以做到这一点,但到目前为止我们还没有找到一个好的方法。任何想法,将不胜感激。
答案 0 :(得分:3)
我无法在手机上轻松测试,但这样的事情应该有效:
pipe(
groupBy(prop('id')),
map(pluck('failedReason')),
map(flatten),
map(uniq)
)
<强>更新强>
我只是想在计算机上看这个,并注意到输出并不是你想要的。再添加两个步骤可以解决它:
pipe(
groupBy(prop('id')),
map(pluck('failedReason')),
map(flatten),
map(uniq),
toPairs,
map(zipObj(['id', 'failedReason']))
)
您可以在 Ramda REPL 上看到这一点。
答案 1 :(得分:2)
您可以定义满足Monoid要求的包装类型。然后,您可以使用R.concat
组合类型的值:
// Thing :: { id :: String, failedReason :: Array String } -> Thing
function Thing(record) {
if (!(this instanceof Thing)) return new Thing(record);
this.value = {id: record.id, failedReason: R.uniq(record.failedReason)};
}
// Thing.id :: Thing -> String
Thing.id = function(thing) {
return thing.value.id;
};
// Thing.failedReason :: Thing -> Array String
Thing.failedReason = function(thing) {
return thing.value.failedReason;
};
// Thing.empty :: () -> Thing
Thing.empty = function() {
return Thing({id: '', failedReason: []});
};
// Thing#concat :: Thing ~> Thing -> Thing
Thing.prototype.concat = function(other) {
return Thing({
id: Thing.id(this) || Thing.id(other),
failedReason: R.concat(Thing.failedReason(this), Thing.failedReason(other))
});
};
// f :: Array { id :: String, failedReason :: Array String }
// -> Array { id :: String, failedReason :: Array String }
var f =
R.pipe(R.map(Thing),
R.groupBy(Thing.id),
R.map(R.reduce(R.concat, Thing.empty())),
R.map(R.prop('value')),
R.values);
f([
{id: '001', failedReason: [1000]},
{id: '001', failedReason: [1001]},
{id: '001', failedReason: [1002]},
{id: '001', failedReason: [1000]},
{id: '001', failedReason: [1000, 1003]},
{id: '002', failedReason: [1000]}
]);
// => [{"id": "001", "failedReason": [1000, 1001, 1002, 1003]},
// {"id": "002", "failedReason": [1000]}]
我确定你能给这个类型一个比Thing更好的名字。 ;)
答案 2 :(得分:1)
为了好玩,主要是为了探索Ramda的优点,我试图想出一个&#34;一个衬垫&#34;在 plain ES6 中进行相同的数据转换......我现在完全理解Scott's answer的简单性:D
我认为我会分享我的结果,因为它很好地说明了清晰的API在可读性方面可以做些什么。管道map
,flatten
和uniq
链更容易掌握......
我使用Map
进行分组,使用Set
过滤重复failedReason
。
const data = [ {id: "001", failedReason: [1000]}, {id: "001", failedReason: [1001]}, {id: "001", failedReason: [1002]}, {id: "001", failedReason: [1000]}, {id: "001", failedReason: [1000, 1003]}, {id: "002", failedReason: [1000]} ];
const converted = Array.from(data
.reduce((map, d) => map.set(
d.id, (map.get(d.id) || []).concat(d.failedReason)
), new Map())
.entries())
.map(e => ({ id: e[0], failedReason: Array.from(new Set(e[1])) }));
console.log(converted);
&#13;
如果在东方,MapIterator
和SetIterator
s会有.map
甚至是.toArray
方法,那么代码就会有点过了清洁剂。