在JavaScript中递归遍历数组并修改对象属性的值

在JavaScript中递归遍历数组并修改对象属性的值,javascript,node.js,algorithm,recursion,data-structures,Javascript,Node.js,Algorithm,Recursion,Data Structures,这篇文章可能看起来很长,但很容易理解,如果没有,我会补充更多细节 我有标准数组,它看起来像: let criteria = [ "and", { "Collection": "persons", "Property": "phone", "operator": "eq&q

这篇文章可能看起来很长,但很容易理解,如果没有,我会补充更多细节

我有
标准
数组,它看起来像:

   let criteria = [
        "and",
        {
          "Collection": "persons",
          "Property": "phone",
          "operator": "eq",
          "operatorValue": "$p:phone"  
        },
        {
          "Collection": "persondetails",
          "Property": "country",
          "operator": "eq",
          "operatorValue": "$p:country" 
        },
        ["or",
        {
          "Collection": "persons",
          "Property": "city",
          "operator": "eq",
          "operatorValue": "$p:city"  
        }]
      ]
标准的特征:

[
    "and",
    {
      "Collection": "persons",
      "Property": "phone",
      "operator": "eq",
      "operatorValue": "23138213"  
    },
    {
      "Collection": "persondetails",
      "Property": "country",
      "operator": "eq",
      "operatorValue": "Russia" 
    },
    ["or",
    {
      "Collection": "persons",
      "Property": "city",
      "operator": "eq",
      "operatorValue": "york"  
    }]
  ]
  function traverse(obj,parameters){
  
    obj.forEach((item,index)=>{
      
      
     if( typeof item == 'string' ){
       //do nothing
     }
     else if( !(item instanceof Array)){
         
       Object.entries(item).forEach((item,index)=>{
         
         if( item[1] instanceof Array){ 
                      
           traverse(item,parameters);
         }else{
           if(item[1].startsWith('$p:')){
               item[1]=parameters[item[1].split('$p:')[1]] //values dont get replaced for obvious reason
               console.log(item[1])
           } 
         }
       })        
     }
     else if( item  instanceof Array){           
           traverse(item,parameters);
      }  
    })
  }

  traverse(criteria,parameters)
  console.log(criteria)
  • 它可以有嵌套的数组
  • 第一项数组(或嵌套数组)始终为“and”或“or”
  • 第二项在数组中向前,该项可以是具有此特定结构的对象
  • {“集合”:“个人”、“财产”:“电话”、“运营商”:“eq”、“运营商价值”:“$p:phone”}

    或者它可以是一个数组,如:

    [“或”、{“集合”:“人员”、“财产”:“城市”、“运营商”:“eq”、“运营商价值”:“$p:city”}]

  • 对象永远不会是嵌套对象
  • 还有一个
    参数
    对象:

    let parameters = {phone:"23138213", "country": "Russia", "city":"york"}
    
    其目的是递归遍历
    条件
    数组中的所有
    运算符值
    属性,如果遇到值,如
    $p:phone
    ,则该值将替换为计算到的任何
    参数[“phone”]

    预期输出:

    [
        "and",
        {
          "Collection": "persons",
          "Property": "phone",
          "operator": "eq",
          "operatorValue": "23138213"  
        },
        {
          "Collection": "persondetails",
          "Property": "country",
          "operator": "eq",
          "operatorValue": "Russia" 
        },
        ["or",
        {
          "Collection": "persons",
          "Property": "city",
          "operator": "eq",
          "operatorValue": "york"  
        }]
      ]
    
      function traverse(obj,parameters){
      
        obj.forEach((item,index)=>{
          
          
         if( typeof item == 'string' ){
           //do nothing
         }
         else if( !(item instanceof Array)){
             
           Object.entries(item).forEach((item,index)=>{
             
             if( item[1] instanceof Array){ 
                          
               traverse(item,parameters);
             }else{
               if(item[1].startsWith('$p:')){
                   item[1]=parameters[item[1].split('$p:')[1]] //values dont get replaced for obvious reason
                   console.log(item[1])
               } 
             }
           })        
         }
         else if( item  instanceof Array){           
               traverse(item,parameters);
          }  
        })
      }
    
      traverse(criteria,parameters)
      console.log(criteria)
    
    我能够递归地遍历数组。唯一的问题是我不知道如何修改原始的
    标准
    变量

    请参见回复中的第43行<代码>项目[1]=参数[项目[1]。拆分(“$p:”)[1]
    我理解为什么它不会修改标准,因为这里的项在不同的范围内是一个不同的变量

    尝试失败:

    [
        "and",
        {
          "Collection": "persons",
          "Property": "phone",
          "operator": "eq",
          "operatorValue": "23138213"  
        },
        {
          "Collection": "persondetails",
          "Property": "country",
          "operator": "eq",
          "operatorValue": "Russia" 
        },
        ["or",
        {
          "Collection": "persons",
          "Property": "city",
          "operator": "eq",
          "operatorValue": "york"  
        }]
      ]
    
      function traverse(obj,parameters){
      
        obj.forEach((item,index)=>{
          
          
         if( typeof item == 'string' ){
           //do nothing
         }
         else if( !(item instanceof Array)){
             
           Object.entries(item).forEach((item,index)=>{
             
             if( item[1] instanceof Array){ 
                          
               traverse(item,parameters);
             }else{
               if(item[1].startsWith('$p:')){
                   item[1]=parameters[item[1].split('$p:')[1]] //values dont get replaced for obvious reason
                   console.log(item[1])
               } 
             }
           })        
         }
         else if( item  instanceof Array){           
               traverse(item,parameters);
          }  
        })
      }
    
      traverse(criteria,parameters)
      console.log(criteria)
    

    如何着手解决这个问题?

    您可以简化您的函数。您不需要遍历对象的条目。您也不需要
    拆分
    操作值
    属性
    键中存在
    参数
    的映射键

    • 循环遍历数组中的每个项,并检查该项是否为
      数组
    • 如果是,则递归调用项目上的
      遍历
    • 如果它是一个对象,则使用
      参数[val.property]
    函数遍历(arr,参数){
    用于(arr的施工项目){
    if(阵列isArray(项目))
    遍历(项目、参数)
    else if(项目类型==='object')
    item.operatorValue=参数[item.Property]
    }
    返回arr
    }
    让标准=[“和”],{集合:“人”,财产:“电话”,接线员:“eq”,接线员价值:$p:phone},{集合:“个人信息”,财产:“国家”,接线员:“eq”,接线员价值:$p:country”},[“或”,{集合:“人”,财产:“城市”,接线员:“eq”,接线员价值:$p:city”}],
    参数={电话:“23138213”,“国家”:“俄罗斯”,“城市”:“约克”};
    
    log(遍历(标准、参数))
    您需要获取对象的键来分配值

    功能遍历(obj,参数){
    对象forEach(项目=>{
    if(数组的项实例)返回遍历(项、参数);
    如果(项目?.operatorValue?.startsWith($p:)){
    item.operatorValue=参数[item.operatorValue.split(“$p:”)[1];
    }
    });
    }
    常数
    标准=[“和”],{集合:“人”,财产:“电话”,接线员:“eq”,接线员价值:$p:phone”},{集合:“个人信息”,财产:“国家”,接线员:“eq”,接线员价值:$p:country”},[“或”,{集合:“人”,财产:“城市”,接线员:“eq”,接线员价值:$p:city”}],
    参数={电话:“23138213”,“国家”:“俄罗斯”,“城市”:“约克”};
    导线测量(标准、参数);
    控制台日志(标准)
    
    .as控制台包装{max height:100%!important;top:0;}
    一个干净的递归版本:

    const traverse=([conj,…nodes],params)=>[
    conj,
    …nodes.map(node=>Array.isArray(node)
    ?导线测量(节点、参数)
    :{…节点,运算符值:params[nodes.Property]}
    )
    ]
    const-criteria=[“and”],{集合:“person”,属性:“phone”,操作符:“eq”,操作符值:$p:phone”},{集合:“persondetails”,属性:“country”,操作符:“eq”,操作符值:$p:country”},[“or”,{集合:“person”,属性:“city”,操作符:“eq”,操作符值:$p:city”}]
    const参数={电话:“23138213”,“国家”:“俄罗斯”,“城市”:“约克”}
    console.log(遍历(标准、参数))
    .as控制台包装{min height:100%!important;top:0}
    下面是一个使用的解决方案。根据您的需求,可能会更加灵活和易于维护

    //const objectScan=require('object-scan');
    const-criteria=['and',{Collection:'persons',Property:'phone',operator:'eq',operator:'p:phone'},{Collection:'personates',Property:'city',operator:'eq',operator:'p:city'};
    常量替换=(对象,参数)=>objectScan(['**.operatorValue']{
    rtn:'计数',
    filterFn:({value,parent,property})=>{
    if(value.startsWith(“$p:”)&参数中的value.slice(3){
    父级[属性]=参数[值.切片(3)];
    返回true;
    }
    返回false;
    }
    })(obj);
    log(替换(标准,{phone:'23138213',country:'rusia',city:'york');//返回替换数
    // => 3
    控制台日志(标准);
    //=>['和',{收集:'人',财产:'电话',接线员:'eq',接线员价值:'23138213'},{收集:'persondetails',财产:'country',接线员:'eq',接线员价值:'york'},['或',{收集:'persons',财产:'city',接线员:'eq',接线员价值:'york'}]
    。作为控制台包装{最大高度:100%!重要;顶部:0}

    我想知道为什么这样做有效,但我的解决方案无效。是因为obj.forEach吗((