以下脚本创建一个过滤某些输入数据的对象。
它使用多个嵌套forEach
以声明方式编码。
我想知道在使用ramdajs或lodash重写此代码时使用哪个API,特别是我有兴趣了解在这种情况下是否适合使用pipe另一种方式。
代码的示例将是欣赏的(特别是对于ramdajs)。感谢。
var data = {
"type": "stylesheet",
"stylesheet": {
"rules": [{
"type": "keyframes",
"name": "bounce",
"keyframes": [{
"type": "keyframe",
"values": [
"from",
"20%",
"53%",
"80%",
"to"
],
"declarations": [{
"type": "declaration",
"property": "animation-timing-function",
"value": "cubic-bezier(0.215, 0.610, 0.355, 1.000)",
"position": {
"start": {
"line": 3,
"column": 5
},
"end": {
"line": 3,
"column": 72
}
}
}, {
"type": "declaration",
"property": "transform",
"value": "translate3d(0,0,0)",
"position": {
"start": {
"line": 4,
"column": 5
},
"end": {
"line": 4,
"column": 34
}
}
}],
"position": {
"start": {
"line": 2,
"column": 3
},
"end": {
"line": 5,
"column": 4
}
}
}, {
"type": "keyframe",
"values": [
"40%",
"43%"
],
"declarations": [{
"type": "declaration",
"property": "animation-timing-function",
"value": "cubic-bezier(0.755, 0.050, 0.855, 0.060)",
"position": {
"start": {
"line": 8,
"column": 5
},
"end": {
"line": 8,
"column": 72
}
}
}, {
"type": "declaration",
"property": "transform",
"value": "translate3d(0, -30px, 0)",
"position": {
"start": {
"line": 9,
"column": 5
},
"end": {
"line": 9,
"column": 40
}
}
}],
"position": {
"start": {
"line": 7,
"column": 3
},
"end": {
"line": 10,
"column": 4
}
}
}, {
"type": "keyframe",
"values": [
"70%"
],
"declarations": [{
"type": "declaration",
"property": "animation-timing-function",
"value": "cubic-bezier(0.755, 0.050, 0.855, 0.060)",
"position": {
"start": {
"line": 13,
"column": 5
},
"end": {
"line": 13,
"column": 72
}
}
}, {
"type": "declaration",
"property": "transform",
"value": "translate3d(0, -15px, 0)",
"position": {
"start": {
"line": 14,
"column": 5
},
"end": {
"line": 14,
"column": 40
}
}
}],
"position": {
"start": {
"line": 12,
"column": 3
},
"end": {
"line": 15,
"column": 4
}
}
}, {
"type": "keyframe",
"values": [
"90%"
],
"declarations": [{
"type": "declaration",
"property": "transform",
"value": "translate3d(0,-4px,0)",
"position": {
"start": {
"line": 18,
"column": 5
},
"end": {
"line": 18,
"column": 37
}
}
}],
"position": {
"start": {
"line": 17,
"column": 3
},
"end": {
"line": 19,
"column": 4
}
}
}],
"position": {
"start": {
"line": 1,
"column": 1
},
"end": {
"line": 20,
"column": 2
}
}
}, {
"type": "rule",
"selectors": [
".bounce"
],
"declarations": [{
"type": "declaration",
"property": "animation-name",
"value": "bounce",
"position": {
"start": {
"line": 23,
"column": 3
},
"end": {
"line": 23,
"column": 25
}
}
}, {
"type": "declaration",
"property": "transform-origin",
"value": "center bottom",
"position": {
"start": {
"line": 24,
"column": 3
},
"end": {
"line": 24,
"column": 34
}
}
}],
"position": {
"start": {
"line": 22,
"column": 1
},
"end": {
"line": 25,
"column": 2
}
}
}, {
"type": "keyframes",
"name": "spark",
"keyframes": [{
"type": "keyframe",
"values": [
"0%",
"50%"
],
"declarations": [{
"type": "declaration",
"property": "transform",
"value": "translate3d(0,0,0)",
"position": {
"start": {
"line": 29,
"column": 5
},
"end": {
"line": 29,
"column": 34
}
}
}],
"position": {
"start": {
"line": 28,
"column": 3
},
"end": {
"line": 30,
"column": 4
}
}
}, {
"type": "keyframe",
"values": [
"100%"
],
"declarations": [{
"type": "declaration",
"property": "transform",
"value": "translate3d(0,-4px,0)",
"position": {
"start": {
"line": 32,
"column": 5
},
"end": {
"line": 32,
"column": 37
}
}
}],
"position": {
"start": {
"line": 31,
"column": 3
},
"end": {
"line": 33,
"column": 4
}
}
}],
"position": {
"start": {
"line": 27,
"column": 1
},
"end": {
"line": 34,
"column": 2
}
}
}, {
"type": "rule",
"selectors": [
".spark"
],
"declarations": [{
"type": "declaration",
"property": "animation-name",
"value": "spark",
"position": {
"start": {
"line": 37,
"column": 3
},
"end": {
"line": 37,
"column": 24
}
}
}, {
"type": "declaration",
"property": "transform-origin",
"value": "center center",
"position": {
"start": {
"line": 38,
"column": 3
},
"end": {
"line": 38,
"column": 34
}
}
}],
"position": {
"start": {
"line": 36,
"column": 1
},
"end": {
"line": 39,
"column": 2
}
}
}],
"parsingErrors": []
}
};
var result = {};
var kfs = data.stylesheet.rules.filter(function(rule) {
return rule.type === 'keyframes'
});
kfs.forEach(function(kf) {
result[kf.name] = [];
kf.keyframes.forEach(function(kfi) {
kfi.values.forEach(function(v) {
var r = {};
var vNew;
vNew = v;
if (v === 'from') {
vNew = 0;
} else if (v === 'to') {
vNew = 100;
} else {
vNew = parseFloat(v);
}
r.offset = vNew;
kfi.declarations.forEach(function(d) {
r[d.property] = d.value;
});
result[kf.name].push(r);
});
});
});
console.log(result);
编辑:
到目前为止,我能够在ramdajs中实现这个结果:
var rulesLense = R.lensPath(['stylesheet', 'rules']);
var ruleView = R.view(rulesLense, obj);
var keyframes = R.filter(R.propEq('type', 'keyframes'));
var groupByKeyframe = R.groupBy(keyframe => {
return R.prop('name', keyframe);
});
var process = R.pipe(
keyframes,
groupByKeyframe
);
var result = process(ruleView);
答案 0 :(得分:1)
我的版本看起来与Yosbel Marin的版本截然不同。
const transform = pipe(
path(['stylesheet', 'rules']),
filter(where({'type': equals('keyframes')})),
groupBy(prop('name')),
map(map(kf => map(kfi => map(v => assoc('offset', cond([
[equals('from'), always(0)],
[equals('to'), always(100)],
[T, parseFloat]
])(v), pipe(
map(lift(objOf)(prop('property'), prop('value'))),
mergeAll
)(kfi.declarations)), kfi.values), kf.keyframes)
)),
map(flatten)
);
我这样做是一个代码端口而根本没有真正理解你的数据。 (我很难这样做,这至少在某种程度上是必要的,但这也是一种有趣的方式。)
前两个步骤应该清楚,它们与之前的答案非常相似。我们从data.stylesheet.rules
获取数据,然后我们将其过滤为仅包含“type”属性为“keyframes”的规则。 (我选择在我的过滤器中使用where
,因为我发现以下内容比propEq
filter(where({'type': equals('keyframes')}))
更具可读性,但它们的工作原理相同。接下来是groupBy(prop('name'))
,这给我们留下了如下结构:
{
bounce: [obj1, obj2, ...]
spark: [objA, objB, ...]
}
下一步是转型的核心。我将原始中的forEach
次调用转换为map
次调用(显然,人们不能总是这样做。)
此:
map(v => map(lift(objOf)(prop('property'), prop('value'))), kfi.declarations)
将声明部分变成类似
的部分[
{"animation-timing-function": "cubic-bezier(0.215, 0.610, 0.355, 1.000)",}
{transform: "translate3d(0,0,0)"},
]
通过提升objOf
函数处理标量值来处理返回这些值的函数,然后传入两个接受声明的函数。然后,这个新函数接受一个声明并返回一个对象。将其映射到声明列表上可获得对象列表。将其与pipe
进行mergeAll
通话会将此类列表转换为单个对象。
此位用一个表达式替换if (v === 'from') { ... } else if ...
代码:
cond([
[equals('from'), always(0)],
[equals('to'), always(100)],
[T, parseFloat]
])(v)
会根据需要返回0
,100
或parseFloat(v)
的结果。
将此与assoc('offset')
以及上一步的结果相结合,我们得到结果中的主要对象,例如:
{
"animation-timing-function": "cubic-bezier(0.215, 0.610, 0.355, 1.000)",
offset: 0,
transform: "translate3d(0,0,0)"
}
唯一要做的就是清理所有这些地图留下的嵌套列表:
{
bounce: [[[obj1, obj2, ...]]]
spark: [[[objA, objB, ...]]]
}
我们通过添加map(flatten)
来完成。
您可以在 Ramda REPL 上看到这一点。
我不知道这是否可以合理地完全没有点数。我猜这充其量是困难的,并且最终会降低可读性。这段代码可能很好地将一些被映射到自己的调用中的函数分解,但我会把它留作读者的练习!