遍历javascript中的缩进数组

Posted

技术标签:

【中文标题】遍历javascript中的缩进数组【英文标题】:Traversing through indented arrays in javascript 【发布时间】:2022-01-19 21:42:25 【问题描述】:

我有一个 javascript 对象如下:

let hogwartsHeirarchy = 
  Headmaster: [
    
      name: "Professor Dumbledore",
      key: 1,
      Headmistress: [
        
          name: "Minerva McGonagall",
          key: 2,
          StandByProfessor: [
            
              name: "Rubeus Hagrid",
              subject: "Potions Master",
              key: 3,
              Professor: [
                 name: "Horace Slughorn", key: 4 ,
                 name: "Severus Snape", key: 4 ,
              ],
            ,
            
              name: "Alastor Moody",
              subject: "Defense Against the Dark Arts",
              key: 3,
              Professor: [
                 name: "Remus Lupin", key: 4 ,
                 name: "Gilderoy Lockhart", key: 4 ,
              ],
            ,
          ],
        ,
      ],
    ,
  ],
;

我想打印/获取每个节点值 [headmaster, headmastress,..] 及其对应的子值。我尝试了各种方法,例如使用 for 循环、递归等遍历数组,但不幸的是我无法从节点中获取任何值。请帮忙。

例如:我用过这个:

printArray(hogwartsHeirarchy);

function printArray(arr)
    for(var i = 0; i < arr.length; i++)
        if(arr[i] instanceof Array)
            console.log("true: ");

            console.log("intermediate one : ",arr[i]);

            printArray(arr[i]);

        else
            console.log("final one : ",arr[i]);
        
    

值可以用这种格式显示:

Headmaster - name : Professor Dumbledore, key : 1
.
.
StandByProfessor - name : Robeus Hagrid, subject : Potion Master, key : 3
StandByProfessor - name : Alastor Moody, subject : Defence against the dark arts, key : 3
.
.
Professor - ...
Professor - ...
Professor - ...
Professor - ...

【问题讨论】:

请添加想要的结果。看起来怎么样? hogwartsHeirarchy 是一个对象而不是数组。 length 不是对象的属性,因此它将返回 undefined,因此您的 for 循环不会发生迭代。 @peineary .. 我是 javascript 新手,无论如何请帮助遍历这个对象/数组。 @Nina .. 我已经编辑了我的问题,请检查。 为什么不使用具有相同键的数据结构来嵌套对象而不是未知键名? 【参考方案1】:

您可以从对象中删除已知键并获取类型层次结构,然后迭代属性并仅在类型存在时返回类型、名称、主题和键的元组。

const
    getValues = (object, type) => [
        ...(type ? [`$type - name : $object.name, $object.subject ? `subject : $object.subject, ` : ''key : $object.key`] : []),
        ...Object
            .keys(object)
            .filter(k => !['name', 'subject', 'key'].includes(k))
            .flatMap(k => object[k].flatMap(o => getValues(o, k)))
        ],
    hogwartsHierarchy =  Headmaster: [ name: "Professor Dumbledore", key: 1, Headmistress: [ name: "Minerva McGonagall", key: 2, StandByProfessor: [ name: "Rubeus Hagrid", subject: "Potions Master", key: 3, Professor: [ name: "Horace Slughorn", key: 4 ,  name: "Severus Snape", key: 4 ] ,  name: "Alastor Moody", subject: "Defense Against the Dark Arts", key: 3, Professor: [ name: "Remus Lupin", key: 4 ,  name: "Gilderoy Lockhart", key: 4 ] ] ] ] ;

console.log(getValues(hogwartsHierarchy));
.as-console-wrapper  max-height: 100% !important; top: 0; 

【讨论】:

感谢@Nina 的帮助。这段代码看起来有点复杂,而且对我的 javascript 理解来说非常先进。您是否可以按照问题本身所述的格式显示数据?【参考方案2】:

我建议进行重组,以便始终使用相同的键访问下属,从而可以非常简单地访问。我也做到了,所以每个节点都是一个人,顶部没有一个不是人的对象。我留下了变量名,但现在它直接引用了 Dumbledore。

let hogwartsHeirarchy =
  
    name: "Professor Dumbledore",
    role: "Headmaster",
    key: 1,
    subordinates: [
      
        name: "Minerva McGonagall",
        role: "Headmistress",
        key: 2,
        subordinates: [
          
            name: "Rubeus Hagrid",
            role: "StandByProfessor",
            subject: "Potions Master",
            key: 3,
            subordinates: [
               name: "Horace Slughorn", key: 4, role: "Professor" ,
               name: "Severus Snape", key: 4, role: "Professor"  ,
            ],
          ,
          
            name: "Alastor Moody",
            role: "StandByProfessor",
            subject: "Defense Against the Dark Arts",
            key: 3,
            subordinates: [
               name: "Remus Lupin", key: 4, role: "Professor" ,
               name: "Gilderoy Lockhart", key: 4, role: "Professor" ,
            ],
          ,
        ],
      ,
    ],
  ;
function visitStaff(staffMember) 
    if (staffMember.subordinates) 
        for (const subordinate of staffMember.subordinates) 
            visitStaff(subordinate);
        
    
    console.log("Staff member:", staffMember);

visitStaff(hogwartsHeirarchy);

在设置数据结构时,重要的是要考虑如何访问它,以及它的定义部分是什么。在这种情况下,有人是节点,还有(从属)关系,是图的边。

在您的原始代码中,您有一个对象 Headmaster: [...] — 它代表什么?是一个人吗?不;是关系吗?有点,但没有。它定义了关于 Dumbledoor 的一些东西,即他是校长,但没有定义他是 of 的校长是谁或什么。所以它实际上只是描述了 Dumbledoor 的角色/职位,所以它作为个人的财产更有意义。它作为一个对象是多余的。

它有助于对齐您的对象,使它们都代表某些东西。您应该能够描述每个对象和数组是什么。

【讨论】:

@1jo1,非常感谢您简化了结构和解释。这些节点现在更加不言自明,并且采用了正确可读的格式。 编辑:@1jo1,刚刚检查了您提供的解决方案以及解释。谢谢你。最干净的解决方案。【参考方案3】:

给定数据结构:

a) 我假设每种“标题”类型中只有一个数组,并且 b) 该数组将包含与其父级结构相似的对象列表

有可能……

    使用for..of 以便 遍历对象上的每个键,并将它们添加到字符串中。因为存在包含对象的数组, 我可以遍历它们,并且 通过让方法调用自身来执行递归循环。

const hogwartsHierarchy =  Headmaster: [ name: "Professor Dumbledore", key: 1, Headmistress: [ name: "Minerva McGonagall", key: 2, StandByProfessor: [ name: "Rubeus Hagrid", subject: "Potions Master", key: 3, Professor: [ name: "Horace Slughorn", key: 4 ,  name: "Severus Snape", key: 4 ] ,  name: "Alastor Moody", subject: "Defense Against the Dark Arts", key: 3, Professor: [ name: "Remus Lupin", key: 4 ,  name: "Gilderoy Lockhart", key: 4 ] ] ] ] ;

function printAllWithChilds(obj, prevProp) 
  let listItem = (prevProp) ? ' -- ' + prevProp : '';
  
  for (const property in obj)     // 1
    if (obj[property] instanceof Array) 
       obj[property].forEach((child_obj) =>                    // 3
         listItem += printAllWithChilds(child_obj, property);   // 4
       );
     else 
      listItem += `, $property: $obj[property]`;            // 2
    
  
  
  return listItem;


let listStr = printAllWithChilds(hogwartsHierarchy);
console.log(listStr);

我会诚实地将hogwartsHierarchy 拆分成更小的部分,遵循一种数据库结构,其中primary_key 对于每个人都是唯一的。这些数组没有多大意义,直到您查看变量professors 以及它们各自的belongs_to 键如何对应于standbyprofessors,您可以在其中看到“Horace Slughorn”属于“Rubeus Hagrid”。

const headermaster = 
  name: "Professor Dumbledore",
  primary_key: 1
;

const headmistress = 
  name: "Minerva McGonagall",
  primary_key: 2,
  belongs_to: 1
;

const standbyprofessors = [
    name: "Rubeus Hagrid",
    subject: "Potions Master",
    primary_key: 3,
    belongs_to: 2
  ,
  
    name: "Alastor Moody",
    subject: "Defense Against the Dark Arts",
    primary_key: 4,
    belongs_to: 2
  
];

const professors = [
    name: "Horace Slughorn",
    primary_key: 5,
    belongs_to: 3
  ,
  
    name: "Severus Snape",
    primary_key: 6,
    belongs_to: 3
  ,
  
    name: "Remus Lupin",
    primary_key: 7,
    belongs_to: 4
  ,
  
    name: "Gilderoy Lockhart",
    primary_key: 8,
    belongs_to: 4
  ,
];

【讨论】:

感谢@Rickard 的所有解释和解决方案。我个人希望按照您的解释划分这个基于大型节点的结构,但是,客户端仅按照问题中的描述以特定格式向我们提供数据。我也尝试过仅使用递归方法进行初始解析,我们是否可以期望递归比 FFire 和 Lina 讨论的方法更高效? FFire 的代码看起来和我的一样高效,因为我的代码只循环一次。 Nina 包含keys, filter, includes and flatmap(两次),它们本身都是循环,这表明代码不够充足。【参考方案4】:

基于1j01 对象模型:

const hogwartsHeirarchy =
  name: "Professor Dumbledore", role: "Headmaster", key: 1,
    subordinates: [ name: "Minerva McGonagall", role: "Headmistress", key: 2,
        subordinates: [
           name: "Rubeus Hagrid", role: "StandByProfessor", subject: "Potions Master", key: 3,
            subordinates: [
               name: "Horace Slughorn", key: 4, role: "Professor" ,
               name: "Severus Snape", key: 4, role: "Professor"  ],
           name: "Alastor Moody", role: "StandByProfessor", subject: "Defense Against the Dark Arts", key: 3,
            subordinates: [
               name: "Remus Lupin", key: 4, role: "Professor" ,
               name: "Gilderoy Lockhart", key: 4, role: "Professor" ]]];
  
  
const visitStaff = (staffMember) => 
  const iter = (obj) => 
    const  name, role, key, subordinates  = obj;
    const subject = obj.subject ? `, subject : $obj.subject` : '';
    const line = `$role - name : $name$subject, key : $key`;
    const sublines = (Array.isArray(subordinates)) ? subordinates.flatMap(iter) : [];
    return [line, ...sublines];
  
  return iter(staffMember).join('\n');

console.log(visitStaff(hogwartsHeirarchy));
.as-console-wrapper  max-height: 100% !important; top: 0; 

【讨论】:

非常感谢@FFire,这看起来像是一个完整的解决方案!我对javascript中的flatmap等属性仍然很陌生。 javascript中是否有任何适当的参考/库可以使这些任务自动化?现在,我们正在手动解析/循环每个节点。 @RahulK,没有外部库,比如lodash等,只有vanila JS

以上是关于遍历javascript中的缩进数组的主要内容,如果未能解决你的问题,请参考以下文章

使用map方法Javascript遍历数组中的所有数组索引

无法使用 javascript 中的 Promise 遍历问题数组中的每个项目

JavaScript中的数组遍历forEach()与map()方法以及兼容写法

如何遍历两个数组的对象作为JavaScript中的以下输出

javascript中的IndexOf方法比遍历数组更有效吗?

遍历一个数组,将每个项目添加到一个对象并将其推送到 Javascript 中的数组