JSON对象中的递归数据
Posted
技术标签:
【中文标题】JSON对象中的递归数据【英文标题】:Recursive data in JSON object 【发布时间】:2020-05-30 09:59:47 【问题描述】:
"groups": [
"name": "Event",
"groups": [
"name": "Service",
"subscriptions": [
"topic": "SERVICE_STATUS_PRESETS"
,
"topic": "AIRCRAFT_ACTIVATION",
,
"topic": "OUT_OF_SERVICE",
]
]
,
"name": "Enquiries",
"groups": [
"name": "Service-related",
"subscriptions": [
"topic": "PROMO_CODES_REQUESTS",
]
]
],
"subscriptions": [
"topic": "BANNERS",
,
"topic": "DOCUMENTS",
,
"topic": "USER",
]
好的,伙计们,我有这样的 JSON 结构,我需要的是:返回数组中的所有主题,在这个例子中它将是:
[“SERVICE_STATUS_PRESETS”、“AIRCRAFT_ACTIVATION”、“OUT_OF_SERVICE”、“PROMO_CODES_REQUESTS”、“BANNERS”、“DOCUMENTS”、“USER”]
我尝试这样的递归调用,虽然我只得到最后三个记录:
getRecursive()
if (Array.isArray(data))
for (let i = 0; i < data.length; i++)
if (data[i].subscriptions)
return data[i].subscriptions.map((val: SubscriptionGroupDetails) => val.topic);
else if (data[i].groups)
return this.getAllTopics(data[i].groups);
if (data && data.groups)
return this.getAllTopics(data.groups);
return data.subscriptions.map((val: SubscriptionGroupDetails) => val.topic);
【问题讨论】:
***.com/questions/11922383/… @Teemu:这看起来并不特别相关。 @ScottSauyet 也许不是,但在提供的示例中没有递归(至少很明显),也许链接帖子中的答案给出了一些想法。 【参考方案1】:您可以采用递归方法并检查
如果传递过来的数据不是检查对象,则返回空数组, 如果对象有想要的属性,则返回一个值为topic
的数组,
或获取值并使用函数进行递归调用,并返回一个包含结果的数组。
function getTopics(object)
if (!object || typeof object !== 'object') return [];
if ('topic' in object) return [object.topic];
return Object.values(object).reduce((r, v) => [...r, ...getTopics(v)], []);
var data = groups: [ name: "Event", groups: [ name: "Service", subscriptions: [ topic: "SERVICE_STATUS_PRESETS" , topic: "AIRCRAFT_ACTIVATION" , topic: "OUT_OF_SERVICE" ] ] , name: "Enquiries", groups: [ name: "Service-related", subscriptions: [ topic: "PROMO_CODES_REQUESTS" ] ] ], subscriptions: [ topic: "BANNERS" , topic: "DOCUMENTS" , topic: "USER" ] ,
result = getTopics(data);
console.log(result);
【讨论】:
【参考方案2】:这是使用object-scan的解决方案
// const objectScan = require('object-scan');
const data = "groups":["name":"Event","groups":["name":"Service","subscriptions":["topic":"SERVICE_STATUS_PRESETS","topic":"AIRCRAFT_ACTIVATION","topic":"OUT_OF_SERVICE"]],"name":"Enquiries","groups":["name":"Service-related","subscriptions":["topic":"PROMO_CODES_REQUESTS"]]],"subscriptions":["topic":"BANNERS","topic":"DOCUMENTS","topic":"USER"];
const searchTopics = (obj) => objectScan(['**.topic'], rtn: 'value' )(obj);
console.log(searchTopics(data));
/* => [
'USER',
'DOCUMENTS',
'BANNERS',
'PROMO_CODES_REQUESTS',
'OUT_OF_SERVICE',
'AIRCRAFT_ACTIVATION',
'SERVICE_STATUS_PRESETS'
] */
.as-console-wrapper max-height: 100% !important; top: 0
<script src="https://bundle.run/object-scan@13.7.1"></script>
免责声明:我是object-scan的作者
【讨论】:
【参考方案3】:如果您有兴趣,此版本将采用功能方法。上面还有其他的,但这只是另一种看待它的方式。
const recursion = object => Object.entries(object).map(([a, b]) =>
if (a === 'topic') return b;
if (Array.isArray(b)) return b.map(recursion);
return [];
).flat(Infinity);
recursion(obj);
【讨论】:
将map()
换成flatMap()
(并在此函数中删除.flat(Infinity)
以获得轻微的性能提升:developer.mozilla.org/en-US/docs/Web/javascript/Reference/…【参考方案4】:
编辑:添加了另一种使用 .reduce()
的方法您可以创建一个topics
的空数组,然后递归地浏览嵌套结构,每次遇到它时添加一个主题,使用javascript .forEach() 循环浏览任何嵌套的groups
或subscriptions
.
let topics = [];
let findTopics = obj =>
if (obj.groups)
obj.groups.forEach(findTopics);
if (obj.subscriptions)
obj.subscriptions.forEach(findTopics);
if (obj.topic)
topics.push(obj.topic);
findTopics(data);
或者使用.reduce() 的一种可能更简洁的方式:
let findTopicsRecursive = (topics, obj) =>
if (obj.groups)
topics = obj.groups.reduce(findTopicsRecursive, topics);
if (obj.subscriptions)
topics = obj.subscriptions.reduce(findTopicsRecursive, topics);
if (obj.topic)
topics.push(obj.topic);
return topics;
let findTopics = data => findTopicsRecursive([], data);
let topics = findTopics(data);
【讨论】:
@YosefTukachinsky 你的意思是说这段代码非常依赖特定的数据结构? 是的,这就是我的意思 @calarin:查看其他一些答案,了解更通用的技术。 @scottsauyet YosefTukachinsky 是的,我明白你的意思!【参考方案5】:使用这个:
function getTopics(obj)
if(typeof obj !== 'object') return [];
if(obj.topic) return [obj.topic];
var res = [];
for(var i in obj)
res.push(...getTopics(obj[i]));
return res;
工作示例:
const topics =
"groups": [
"name": "Event",
"groups": [
"name": "Service",
"subscriptions": [
"topic": "SERVICE_STATUS_PRESETS"
,
"topic": "AIRCRAFT_ACTIVATION",
,
"topic": "OUT_OF_SERVICE",
]
]
,
"name": "Enquiries",
"groups": [
"name": "Service-related",
"subscriptions": [
"topic": "PROMO_CODES_REQUESTS",
]
]
],
"subscriptions": [
"topic": "BANNERS",
,
"topic": "DOCUMENTS",
,
"topic": "USER",
]
function getTopics(obj)
if(typeof obj !== 'object') return [];
if(obj.topic) return [obj.topic];
var res = [];
for(var i in obj)
res.push(...getTopics(obj[i]));
return res;
console.log(getTopics(topics));
【讨论】:
以上是关于JSON对象中的递归数据的主要内容,如果未能解决你的问题,请参考以下文章