我试图学习一些关于函数式编程和Ramda的知识,并且正在使用我最喜欢的数据结构操作来尝试一些免费的东西。很少或没有循环。我的输入数据:
const data = [{
timeline_map: {
"2017-05-06": 770,
"2017-05-07": 760,
"2017-05-08": 1250,
}
}, {
timeline_map: {
"2017-05-06": 590,
"2017-05-07": 210,
"2017-05-08": 300,
}
}, {
timeline_map: {
"2017-05-06": 890,
"2017-05-07": 2200,
"2017-05-08": 1032,
}
}]
期望的输出:
[
["2017-05-06", 770, 590, 890, ...],
["2017-05-07", 760, 210, 2200, ...],
["2017-05-08", 1250, 300, 1032, ...]
]
这是我的代码:
const condense = x => x.timeline_map
var rest = []
const pluckDate = (obj, i) => {
return [Object.keys(obj)[i]]
}
const getValues = value => {
data.map(function () {
return data.timeline_map
})
}
const result = R.compose(
R.values,
R.mapObjIndexed(pluckDate),
R.map(condense)
)
console.log(result(data))
到目前为止,我所得到的只是提取的日期:
[["2017-05-06"], ["2017-05-07"], ["2017-05-08"]]
这仍然远离解决方案和我不知道我是否已经在"好"办法。什么是"功能" /" ramda" /"点免费"解决这个问题的方法?
答案 0 :(得分:3)
这是一种方法。可能有一个更简单的一个:
const convert = pipe(
pluck('timeline_map'), //=> [{"2017-05-06": 770, "2017-05-07": 760, ...}, ...]
map(toPairs), //=> [[["2017-05-06", 770], ["2017-05-07", 760], ...], ...]
unnest, //=> [["2017-05-06", 770], ["2017-05-07", 760], ...]
groupBy(head), //=> {"2017-05-06": [["2017-05-06", 770], ["2017-05-06", 590], ...], "2017-05-07": [...], ...}
map(map(last)), //=> {"2017-05-06": [770, 590, 890], "2017-05-07": [760, 210, 2200], ...]
toPairs, //=> [["2017-05-06", [770, 590, 890]], ["2017-05-07", [760, 210, 2200]], ...]
map(apply(prepend)) //=> [["2017-05-06", 770, 590, 890], ["2017-05-07", 760, 210, 2200], ...]
)
convert(data)
这涉及许多不同的步骤,我已经展示了每个生成的数据类型。
您可以在 Ramda REPL 上看到这一点。
答案 1 :(得分:2)
只是为了好玩,我想尝试在一个循环中使用两个嵌套的reducer进行。有三个原因我认为我会分享我的想法:
reduce
操作的组合:从{ timeline_map }
到[entries]
,从[entries]
到[[key, ...values]]
< / LI>
可能有趣的是看两个减少的,变异的Map
方法是否也可以组成一个无点的Ramda函数......但是我不是那个想出来的人。
// from [[key, value]] to Map(key, [key, values])
const timeLineReducer = (map, [key, value]) =>
map.set(
key,
(map.get(key) || [key]).concat(value)
);
// From [{ key: value }] to Map(key, [key, values])
const dataReducer = (map, { timeline_map }) =>
Object
.entries(timeline_map)
.reduce(timeLineReducer, map);
const transformData = data => Array.from(
data
.reduce(dataReducer, new Map())
.values()
);
console.log(transformData(getData()))
// data
function getData() { return [{timeline_map:{"2017-05-06":770,"2017-05-07":760,"2017-05-08":1250}},{timeline_map:{"2017-05-06":590,"2017-05-07":210,"2017-05-08":300}},{timeline_map:{"2017-05-06":890,"2017-05-07":2200,"2017-05-08":1032}}]; }
编辑:出于好奇,我想去点免费编程。一个有趣的谜题,但我不能说我真的很感激结果。
之前没试过,所以我甚至不确定它 是否免费。但它有效!
// e.g.: [2] -> [1] -> [1, 2]
const fConcat = flip(concat);
// e.g. : [1, 3] -> [1, 2] -> [1, 2, 3]
const fConcatTail = useWith(fConcat, [tail, identity]);
// e.g.: secNil(1, null) -> true
const secNil = compose(isNil, nthArg(1));
// e.g.: fConcatTailIf([0, 1], null) -> [0, 1]
// e.g.: fConcatTailIf([0, 2], [0, 1]) -> [0, 1, 2]
const fConcatTailIf = ifElse(
secNil,
clone,
fConcatTail
);
// e.g.: ["a", 1] -> lensProp("a")
const kvpKeyLensProp = compose(lensProp, head);
// e.g.: ["a", 1] -> {} -> { a: ["a", 1] }
// e.g.: ["a", 2] -> { a: ["a", 1] } -> { a: ["a", 1, 2]}
const handleKVP = compose(
apply(over), // create over that waits for {}
ap([kvpKeyLensProp, fConcatTailIf]), // ap with arg.
of // wrap argument in array
);
// (kvp, map) => handleKVP(kvp)(map);
const mergeKVPWithMap = uncurryN(2, handleKVP);
// Flip because reduce is inverted ((map, kvp) => ...)
// e.g.: {} -> ["a", 1] -> { a: ["a", 1]}
const entryReducer = flip(mergeKVPWithMap);
// e.g.: {} -> [ ["a", 1] ] -> { a: ["a", 1] }
// e.g.: { a: ["a", 1] } -> [ ["a", 2] ] -> { a: ["a", 1, 2] }
const timelineReducer = reduce(entryReducer);
// e.g. { timeline_map: { a: 1 } } -> [ [ "a", 1 ] ]
const entriesFromData = compose(toPairs, prop("timeline_map"));
// Decorate 2nd argument of timelineReducer with entriesFromData
const dataReducer = useWith(timelineReducer, [identity, entriesFromData]);
// Return only the values from our composed object
const transformData = compose(values, reduce(dataReducer, { }));
// Call our transformation with our data
transformData(getData())
// data
function getData() { return [{timeline_map:{"2017-05-06":770,"2017-05-07":760,"2017-05-08":1250}},{timeline_map:{"2017-05-06":590,"2017-05-07":210,"2017-05-08":300}},{timeline_map:{"2017-05-06":890,"2017-05-07":2200,"2017-05-08":1032}}]; }
中试用
答案 2 :(得分:1)
为了演示目的,这是另一种解决方案。
const concatAll = reduce(mergeWith(concat), {});
const wrapInArray = value => [value];
const zipKeysWithValues = (arr) => zip(keys(arr), values(arr));
const res1 = pipe(
pluck('timeline_map'),
map(map(wrapInArray)),
concatAll,
zipKeysWithValues,
map(flatten),
)(data);
const res2 = compose(
map(flatten),
zipKeysWithValues,
concatAll,
map(map(wrapInArray)),
pluck('timeline_map'))(data);
您也可以同时使用pipe
和compose
。对于记录,在任意两个步骤之间使用tap(console.log)
。
答案 3 :(得分:0)
使用纯js的最快方法
var data = [{
timeline_map: {
"2017-05-06": 770,
"2017-05-07": 760,
"2017-05-08": 1250,
}
}, {
timeline_map: {
"2017-05-06": 590,
"2017-05-07": 210,
"2017-05-08": 300,
}
}, {
timeline_map: {
"2017-05-06": 890,
"2017-05-07": 2200,
"2017-05-08": 1032,
}
}];
var mapper = {};
var output = [];
data.forEach((_node) => {
for (let key in _node.timeline_map) {
if (!mapper[key]) {
mapper[key] = [];
}
mapper[key].push(_node.timeline_map[key]);
}
});
for (let key in mapper) {
let row = [key];
row = row.concat(mapper[key]);
output.push(row);
}
console.log(mapper); //"{"2017-05-06":[770,590,890],"2017-05-07":[760,210,2200],"2017-05-08":[1250,300,1032]}"
console.log(output); //[["2017-05-06",770,590,890],["2017-05-07",760,210,2200],["2017-05-08",1250,300,1032]]