繁体   English   中英

将具有特定键和分组值的通用JS集合转换为对象

[英]Transform a generic JS collection to an object with specific keys and grouped values

我想创建一个JS函数,将通用集合(数组或对象的嵌套级别的数组或对象)转换为一个对象,该对象的键是输入数组参数(如果提供的话,如果输入中不是所有不同的对象键,则提供)和value是输入中这些键的叶值数组)。 如果提供了标志,则叶值可以是不同的。

就像是:

transform([{a:1, b:'1', c:true, d:1},{a:'1', b:2, c:3, d:false}, {a:1, c:'test'}], ['a','b','c'], true);

要么

transform({x:{b:2,c:{c:3, d:1}},b:'1',z:{b:2,c:true,a:1},a:'1',g:{c:'test',d:false}}, ['a','b','c'], true);

将产生相同的输出:

{a:[1, '1'], b:['1', 2], c:[true, 3, 'test']} 
  • 第一个参数是集合-必选
  • 第二个是键数组-可选
  • 第三个参数是唯一标志-可选

如果省略第二个参数。 它将产生此:

{a:[1, '1'], b:['1', 2], c:[true, 3, 'test'], d:[1,false]} 

快速和/或优雅的方式是什么?

是否有任何lodash /下划线帮助器。

谢谢。

基础

这个问题的主要部分是递归地遍历对象树并收集值。

为此,我们编写了一个函数,该函数查看一个值并确定它是否是对象。 如果不是,则将值连接到结果数组。 如果是这样,我们将使用相同的逻辑来减小其值。

 const deepValues = (obj, res = []) => isObject(obj) ? Object.values(obj).reduce(flip(deepValues), res) : res.concat(obj) console.log( deepValues({x:{b:2,c:{c:3, d:1}}}) ); // Utils function flip(f) { return (x, y) => f(y, x) }; function isObject(x) { return Object.prototype.toString.call(x) === "[object Object]" }; 

自订

一旦您了解了此功能,添加其他零碎的部分就会更加有意义。

步骤1:并非所有值...

因此,如果键的值符合我们的标准,我们希望将值连接到结果。

我们在签名中添加了一个keyPred函数,并开始使用[key, value]对,而不仅仅是值。 谓词获取一个键并返回一个布尔值,该布尔值指示是否应存储它。

该函数变得很难读,但与初始函数没有太大区别:

 const certainDeepValues = (keyPred, obj, res = []) => Object.entries(obj) .reduce((r, [k, v]) => isObject(v) ? certainDeepValues(keyPred, v, r) : keyPred(k) ? r.concat(v) : r , res); console.log( certainDeepValues( k => k === "c", {x:{b:2,c:{c:3, d:1}}} ) ); // Utils function isObject(x) { return Object.prototype.toString.call(x) === "[object Object]" }; 

步骤2:仅收集唯一值

Javascript具有用于唯一值集合的完美类型: Set ,这使得这是一个很小的变化。 默认参数为new Setconcat方法变为add

 const certainDeepValues = (keyPred, obj, res = new Set()) => Object.entries(obj) .reduce((r, [k, v]) => isObject(v) ? certainDeepValues(keyPred, v, r) : keyPred(k) ? r.add(v) : r , res); console.log( [...certainDeepValues( k => k === "c", {x:{b:2,c:{c:3, d:1, e: { c: "2" }}}, c: 3} )] ); // Utils function flip(f) { return (x, y) => f(y, x) }; function isObject(x) { return Object.prototype.toString.call(x) === "[object Object]" }; 

您自己的签名

现在,剩下的就是实现所需的签名了。 这是一个有点丑陋的地方,但是由于您没有发布任何尝试,而只是将您的“问题”作为作业分配给我们,因此我将由您自己负责清理:)

 const certainDeepValues = (concat, keyPred, obj, res = new Set()) => Object.entries(obj) .reduce((r, [k, v]) => isObject(v) ? certainDeepValues(concat, keyPred, v, r) : keyPred(k) ? concat(r, k, v) : r , res); const transform = (xs = [], keys = [], uniquesOnly = false) => { const keySet = new Set(keys); const keyPred = keys.length ? k => keySet.has(k) : k => true; const concat = uniquesOnly ? (acc, k, v) => (acc[k] = (acc[k] || new Set()).add(v), acc) : (acc, k, v) => (acc[k] = (acc[k] || []).concat(v), acc) const unwrap = uniquesOnly ? acc => mapObj(s => [...s], acc) : acc => acc; return unwrap(xs.reduce( (r, x) => certainDeepValues(concat, keyPred, x, r), {} )); }; console.log( JSON.stringify( transform([{a:1, b:'1', c:true, d:1},{a:'1', b:2, c:3, d:false}, {a:1, c:'test'}], ['a','b','c'], true) ) ); console.log( JSON.stringify( transform([{x:{b:2,c:{c:3, d:1}},b:'1',z:{b:2,c:true,a:1},a:'1',g:{c:'test',d:false}}], ['a','b','c'], true) ) ); console.log( JSON.stringify( transform([{x:{b:2,c:{c:3, d:1}},b:'1',z:{b:2,c:true,a:1},a:'1',g:{c:'test',d:false}}], undefined, true) ) ); // Utils function mapObj(f, obj) { return Object.assign({}, ...Object.entries(obj).map(([k, v]) => ({[k]: f(v)}))); } function flip(f) { return (x, y) => f(y, x) }; function isObject(x) { return Object.prototype.toString.call(x) === "[object Object]" }; 

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM