我有一些问题(基本的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 JS
或lodash
删除它们。
我的尝试:
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:为清晰起见添加更多信息
该项目使用thunks
和action creator
,所以绝对不是变异原则。我没有提到这个,因为我认为这个特殊问题更像是一个基本的JS基础问题。
此特定代码段在调度之前位于slice()
。
我必须提一下,我之前从getState()
函数参数(还原商店返回的对象)做了arrayB
以获得newArray1
所以基本上我在这里添加的代码是可变的,因为我正在处理一个独特的副本。最终数组(newArray1
)将作为状态的有效负载传递。
因此,如果创建一个新数组(实际上map
是一个新创建的数组,只是为了保存来自过滤操作的数据)或者是否存在(此处添加的代码),这并不重要)数组是突变的。
我还认为创建一个新数组只是为了保存过滤后的数据可能不是必需的,也许可以通过多个链式filter
和react-redux
以及类似方法来解决。但是现在想要在早期开发过程中保持简单。
这是我的第一个selectedskill
项目(学习项目之外),所以我确实要小心改变状态,有时会过度创建副本。
流量:
Promise
数组then
,因此在getState()
我发送基于所选技能显示相关项目的操作slice()
和skillsets
从商店(arrayB
)获取selectedskills
对象的副本所有具备技能和技能的技能组合也包括匹配的项目。我也有arrayA
数组可用(arrayB
)。现在我需要匹配它们并过滤掉嵌套的独占项目(propC
> propC3
> skillsets
)skills
和allprojects
中提取出所有这些项目重复将它们保存为一个大而独特的skillsets
数组,如果需要我可以使用它。我没有像我想的那样使用它,考虑到数据是有限的,所以我的{{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" ]