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
&lt;script src="https://bundle.run/object-scan@13.7.1"&gt;&lt;/script&gt;

免责声明:我是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() 循环浏览任何嵌套的groupssubscriptions .

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对象中的递归数据的主要内容,如果未能解决你的问题,请参考以下文章

java处理json与对象的转化 递归

如何用java递归生成带children的json串

如何用java递归生成带children的json串

如何使用 JSON 数据递归填充 TreeView

递归对象到 JSON

递归解析 JSON