JSON对象中的递归数据

4
{
"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);
}

https://dev59.com/X2ct5IYBdhLWcg3wpfFc - Teemu
@Teemu:那看起来并不特别相关。 - Scott Sauyet
1
@ScottSauyet 或许不是,但是在提供的示例中没有递归(至少不明显),也许链接帖子中的答案可以提供一些思路。 - Teemu
5个回答

5

你可以采用递归的方法进行检查

  • 如果传递的数据不是要检查的对象,则返回空数组,
  • 如果对象具有所需的属性,则返回一个包含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 的作者。


1

use this:

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));


1

如果您感兴趣,这个版本采用的是函数式方法。虽然还有其他方式,但这只是另一种看待它的方式。

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);

1
map() 替换为 flatMap()(并在此函数中删除 .flat(Infinity))以获得轻微的性能提升:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/flatMap - BigBlueHat

0

编辑:使用.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
是的,这正是我所想表达的。 - Yosef Tukachinsky
@calarin:查看其他答案中更通用的实现技巧。 - Scott Sauyet
@scottsauyet YosefTukachinsky 是的,好观点 - 我明白你的意思了! - calarin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接