循环遍历嵌套数组并返回独占结果

时间:2018-04-28 09:14:42

标签: javascript arrays dictionary filter redux

我有一些问题(基本的JS嵌套和过滤)检索'排除'从嵌套数组对象中过滤数据。代码用于React项目。如果需要,我可以介绍lodash。

我有一个数组包含1个或更多(也可能是0,在这种情况下返回默认值)数组中的字符串:

let arrayA = ["string-1", "string-2"]; //assume them to be skill slugs 

我声明了一个新数组来保存稍后推送到其中的数据:

let newArr1 = [];

我的嵌套主数组:

      /*Top level skillset category, within each of which a skills array resides (propC).
        Within each skill there is an array of projects associated with that particular skill (propC3). 
        Projects can have multiple skills so projects in one skill may perhaps reside in other skills as well.*/
     let arrayB =[ //the top level skillset category
        {
        "propA": "valueA1",
        "propB": "valueB1",
        "propC":[ //the skills array
            {
            "propC1": "valueC11",
            "matchthis": "string-1", //the unique skill slug
            "proppC2": "valueC12",

            "propC3": [ //projects
                {
                propC31: "valueC131",
                },
                {
                propC32: "valueC132",
                }

                ]

            },

            {
                "propC1": "valueC12",
                "matchthis": "string-2",
                "proppC2": "valueC12",

                "propC3": [
                    {
                    propC31: "valueC131",
                    },
                    {
                    propC32: "valueC232",
                    }

                    ]

                }

        ],
        "propD": "valueD1"      
        },
        {
        "propA": "valueA2",
        "propB": "valueB2",
        "propC":[
            {
            "propC1": "valueC21",
            "matchthis": "string-2",
            "proppC2": "valueC22",
            "proppC3": [
                {
                propC31: "valueC231",
                },
                {
                propC32: "valueC132",
                }

                ]

            }
        ],
        "propD": "valueD1"      
        },


    ]

我需要过滤我的arrayB嵌套数组,以便只返回基于arrayA数组中字符串的数据子集。我使用newArray1数组来保存这些数据。我可以有重复数据(当我推入newArray数组时),所以我也可以通过vanilla JSlodash删除它们。

我的尝试:

arrayA.map((a,i)=>{
   return arrayB.filter((b,j)=>{
     return b.propC.filter((c,k)=>{
        return a===c.matchthis
       }).map((o,i)=>{
        o.propC3.map((o,i)=>{
         newArr1.push(o)
        })

      })                 
     })
   })

当我推送数据时,可能存在重复,因此我将其删除:

 // newArr1 =  newArr1.filter((s1, pos, arr) => arr.findIndex((s2)=>s2.project_id === s1.project_id) === pos); //JS
 newArr1 = _.uniqBy(newArr1, 'project_id'); //lodash

我似乎无法获得exclusion。依据排他性意味着驻留在newArray1(项目)中的数据应该只有具有arrayA中传递的所有技能的项目 - 如果一个失败则没有结果。如果我已通过["html5", "css", "react"],则只返回包含这些技能的项目。

我可以得到包容性的'结果与我目前的方法一致。

因此,场景是:用户选择一项或多项技能(来自技能系列),并展示包含所有这些技能的项目(独家方法)。由于技能属于类别,技能有时可以存在于多个类别中。我可能有一个开关,允许用户在包容性和独占过滤之间进行选择,但绝对不是现在。

这是或多或少的实际数组对象,为了简洁起见:

       [{
        skillltype_id:”0”,
        skills: [
       {
        skill_id: ”0”,
        skill_name: "HTML5”,    
        skill_slug:"html5”,
        ….
        projects: [
             {
                     project_id :”0”,
                     project_name: “Lorem Ipsum 1”,         
                     project_slug: “a-slug”
                     …
             },

             {
                     project_id :”2”,
                     project_name: “Lorem Ipsum 2”,         
                     project_slug: “b-slug”
                     …
             },
             ….
         ]

     },
     {
     skill_id: ”2”,
     skill_name: “javascript”,
     skill_slug:”javascript”,
    ….
     projects: [
             {
                     project_id :”100”,
                     project_name: “Lorem Ipsum 1”,                      
                     project_slug: “a-slug”
                     …

             },
             {
                     project_id :”2”,
                     project_name: “Lorem Ipsum 2”,                      
                     project_slug: “b-slug”
                     …
             },
             ….
         ]
     }

     ],
     skilltype_description:"Lorem Ipsum”,
     skilltype_name:”Lorem Ipsum”,
     skilltype_shortdescription:"Lorem Ipsum”,
     },

     ……..
     ……

     ]

更新:添加想要的结果:

根据此问题顶部显示的示例数组,将["html5","css"]作为arrayA传递

应该返回一个数组,其中包含arrayB>中包含的项目列表propC> propC3 newArray1 arrayA(或任何名称),matchthis中的每个元素都与propC中的html5属性匹配。

如果只有一个字符串匹配(例如["html5","css"]),那么就不能考虑它并返回一个空数组。所有传递的字符串必须匹配才能被视为独占。

为了更加清晰:基于具有接近实际数据的arrayB示例(在问题的末尾),将skills作为数组传递

应返回projects>中包含的项目数组skill_slug其中每个元素(字符串)与skills数组中的arrayA属性匹配。

  • arrayB是包含值im将用于搜索的数组
  • propC是技能组类别数组,由名为propC的技能数组组成。
  • propC3内的每项技能都包含一个名为matchthis的项目数组,并且还有一个arrayA属性,可用于匹配redux中的字符串。

更新2:为清晰起见添加更多信息

该项目使用thunksaction creator,所以绝对不是变异原则。我没有提到这个,因为我认为这个特殊问题更像是一个基本的JS基础问题。

此特定代码段在调度之前位于slice()

我必须提一下,我之前从getState()函数参数(还原商店返回的对象)做了arrayB以获得newArray1所以基本上我在这里添加的代码是可变的,因为我正在处理一个独特的副本。最终数组(newArray1)将作为状态的有效负载传递。

因此,如果创建一个新数组(实际上map是一个新创建的数组,只是为了保存来自过滤操作的数据)或者是否存在(此处添加的代码),这并不重要)数组是突变的。

我还认为创建一个新数组只是为了保存过滤后的数据可能不是必需的,也许可以通过多个链式filterreact-redux以及类似方法来解决。但是现在想要在早期开发过程中保持简单。

这是我的第一个selectedskill项目(学习项目之外),所以我确实要小心改变状态,有时会过度创建副本。

流量:

  • 用户选择一项技能,我发送一个动作并将技能slug添加到商店中存在的Promise数组
  • 以上是then,因此在getState()我发送基于所选技能显示相关项目的操作
  • 此操作是此问题的来源。我使用slice()skillsets从商店(arrayB)获取selectedskills对象的副本所有具备技能和技能的技能组合也包括匹配的项目。我也有arrayA数组可用(arrayB)。现在我需要匹配它们并过滤掉嵌套的独占项目(propC> propC3> skillsets
  • 假设我得到了我想要的数据(使用新数组或只是多个链接映射和过滤器)我将此数组作为要分配给reducer的有效负载返回,以便我的UI现在将显示与之相关的项目所有选定的技能。
  • (旁注:我有一系列可用的项目。很早,当页面打开时,我从所有skillsallprojects中提取出所有这些项目重复将它们保存为一个大而独特的skillsets数组,如果需要我可以使用它。我没有像我想的那样使用它,考虑到数据是有限的,所以我的{{1}}数组不会太大而且我可以继续使用它作为主要数据来源,并在需要时使用它)

1 个答案:

答案 0 :(得分:1)

所以这是一种做法。首先,我们创建一个Projects对象:

let Projects = {};

现在我们用arrayB中的项目的所有技能要求填写它:

arrayB.map((b) => { 
  b.propC.map((c) => { 
    // note had to use old-style function here to get this to be correctly assigned in Firefox
    c.propC3.map(function (c3) {
      // get the name of the project
      let name = c3[Object.keys(c3)[0]];
      if (Projects.hasOwnProperty(name))
        Projects[name].push(this.toString());
      else
        Projects[name] = [this.toString()];
    }, c.matchthis); 
  }); 
});

在此示例中,console.log(Projects)给出:

{…}
valueC131: Array [ "string-1", "string-2" ]
valueC132: Array [ "string-1", "string-2" ]
valueC231: Array [ "string-2" ]
valueC232: Array [ "string-2" ]
__proto__: Object { … }

现在我们可以简单地将Projects的元素与arrayA中的技能进行比较。任何需要arrayA 全部技能的项目都会被推送到newArr

let newArr = [];
for (p in Projects) {
  if (Projects.hasOwnProperty(p)) {
    if (arrayA.reduce((t, s) => { return t && (Projects[p].indexOf(s) >= 0); }, true)) newArr.push(p);
  }
}
console.log(newArr);

输出:

Array [ "valueC131", "valueC132" ]

我们还可以检查arrayA中需要任何技能的项目,并略微更改代码:

newArr = [];
for (p in Projects) {
  if (Projects.hasOwnProperty(p)) {
    if (arrayA.reduce((t, s) => { return t || (Projects[p].indexOf(s) >= 0); }, false)) newArr.push(p);
  }
}
console.log(newArr);

输出:

Array [ "valueC131", "valueC132", "valueC232", "valueC231" ]