如何基于内部数组过滤外部数组?

时间:2019-05-15 07:04:19

标签: javascript arrays

我有一个像这样的json,我想获得具有几乎一项服务的所有区域,这些区域的selected属性等于true。

{
   "areas": [
      {
         "name": "area 1",
         "services": [
            {
               "label": "srv 1",
               "selected": true
            },
            {
               "label": "srv 2",
               "selected": false
            },
            {
               "label": "srv 3",
               "selected": false
            },
            {
               "label": "srv 4",
               "selected": true
            }
         ]
      },
      {
         "name": "area 2",
         "services": [
            {
               "label": "srv 1",
               "selected": false
            },
            {
               "label": "srv 2",
               "selected": true
            },
            {
               "label": "srv 3",
               "selected": false
            },
            {
               "label": "srv 4",
               "selected": false
            }
         ]
      },
      {
         "name": "area 3",
         "services": [
            {
               "label": "srv 1",
               "selected": false
            },
            {
               "label": "srv 2",
               "selected": false
            },
            {
               "label": "srv 3",
               "selected": false
            }
         ]
      },
      {
         "name": "area 4",
         "services": [
            {
               "label": "srv 1",
               "selected": true
            },
            {
               "label": "srv 2",
               "selected": false
            },
            {
               "label": "srv 3",
               "selected": true
            }
         ]
      }
   ]
}

结果必须仅包含具有所选属性等于true的服务的区域,并且必须指出该区域而不会改变原始数组。

使用此代码

const result = areas.filter(area =>
  services.some(srv => srv.selected == true)
);

我获得了所有区域,但是在这些区域内,我拥有了所有服务(选择为true和选择false)。

这是我想要的:

{
   "areas": [
      {
         "name": "area 1",
         "services": [
            {
               "label": "srv 1",
               "selected": true
            },
            {
               "label": "srv 4",
               "selected": true
            }
         ]
      },
      {
         "name": "area 2",
         "services": [
            {
               "label": "srv 2",
               "selected": true
            }
         ]
      },
      {
         "name": "area 4",
         "services": [
            {
               "label": "srv 1",
               "selected": true
            },
            {
               "label": "srv 3",
               "selected": true
            }
         ]
      }
   ]
}

谢谢

10 个答案:

答案 0 :(得分:2)

为避免变异原始对象,请map的每个input.areas项目将其变成其selected中只有真实services的对象,然后将{{1} } filter属性中是否包含任何项目:

services

答案 1 :(得分:1)

您可以缩小数组,并仅过滤services中经过过滤的部分。

var data = { areas: [{ name: "area 1", services: [{ label: "srv 1", selected: true }, { label: "srv 2", selected: false }, { label: "srv 3", selected: false }, { label: "srv 4", selected: true }] }, { name: "area 2", services: [{ label: "srv 1", selected: false }, { label: "srv 2", selected: true }, { label: "srv 3", selected: false }, { label: "srv 4", selected: false }] }, { name: "area 3", services: [{ label: "srv 1", selected: false }, { label: "srv 2", selected: false }, { label: "srv 3", selected: false }] }, { name: "area 4", services: [{ label: "srv 1", selected: true }, { label: "srv 2", selected: false }, { label: "srv 3", selected: true }] }] },
    result = data.areas.reduce((r, o) => {
        var services = o.services.filter(({ selected }) => selected);
        if (services.length) r.push(Object.assign({}, o, { services }));
        return r;
    }, []);

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

答案 2 :(得分:0)

您可以使用过滤器两次

const res = data.areas.filter(e => {
    e.services = e.services.filter(s => s.selected);
    return e.services.length;
});

console.log(res);
<script>
const data = {
    "areas": [
    {
        "name": "area 1",
        "services": [
            {
                "label": "srv 1",
                "selected": true
            },
            {
                "label": "srv 2",
                "selected": false
            },
            {
                "label": "srv 3",
                "selected": false
            },
            {
                "label": "srv 4",
                "selected": true
            }
        ]
    },
    {
        "name": "area 2",
        "services": [
            {
                "label": "srv 1",
                "selected": false
            },
            {
                "label": "srv 2",
                "selected": true
            },
            {
                "label": "srv 3",
                "selected": false
            },
            {
                "label": "srv 4",
                "selected": false
            }
        ]
    },
    {
        "name": "area 3",
        "services": [
            {
                "label": "srv 1",
                "selected": false
            },
            {
                "label": "srv 2",
                "selected": false
            },
            {
                "label": "srv 3",
                "selected": false
            }
        ]
    },
    {
        "name": "area 4",
        "services": [
            {
                "label": "srv 1",
                "selected": true
            },
            {
                "label": "srv 2",
                "selected": false
            },
            {
                "label": "srv 3",
                "selected": true
            }
        ]
    }
]
}
</script>

答案 3 :(得分:0)

您可以做到

obj.areas.filter(area =>
  area.services = area.services.filter(srv => srv.selected == true)
);

答案 4 :(得分:0)

这应该足够了, 您基本上可以结合使用Array#filter

const filterBySelectedServices = list => list
  .map(area => Object.assign({}, area, {
    services: area.services.filter(service => service.selected),
  }))
  .filter(area => area.services.length);

const data = {
  "areas": [
    {
      "name": "area 1",
      "services": [
        {
          "label": "srv 1",
          "selected": true
        },
        {
          "label": "srv 2",
          "selected": false
        },
        {
          "label": "srv 3",
          "selected": false
        },
        {
          "label": "srv 4",
          "selected": true
        }
      ]
    },
    {
      "name": "area 2",
      "services": [
        {
          "label": "srv 1",
          "selected": false
        },
        {
          "label": "srv 2",
          "selected": true
        },
        {
          "label": "srv 3",
          "selected": false
        },
        {
          "label": "srv 4",
          "selected": false
        }
      ]
    },
    {
      "name": "area 3",
      "services": [
        {
          "label": "srv 1",
          "selected": false
        },
        {
          "label": "srv 2",
          "selected": false
        },
        {
          "label": "srv 3",
          "selected": false
        }
      ]
    },
    {
      "name": "area 4",
      "services": [
        {
          "label": "srv 1",
          "selected": true
        },
        {
          "label": "srv 2",
          "selected": false
        },
        {
          "label": "srv 3",
          "selected": true
        }
      ]
    }
  ]
};

console.log('result', filterBySelectedServices(data.areas));

答案 5 :(得分:0)

您可以使用reducefilter并仅采用过滤后服务中包含某些项目的那些元素

let data = {"areas": [{"name": "area 1","services": [{"label": "srv 1","selected": true},{"label": "srv 2","selected": false},{"label": "srv 3","selected": false},{"label": "srv 4","selected": true}]},{"name": "area 2","services": [{"label": "srv 1","selected": false},{"label": "srv 2","selected": true},{"label": "srv 3","selected": false},{"label": "srv 4","selected": false}]},{"name": "area 3","services": [{"label": "srv 1","selected": false},{"label": "srv 2","selected": false},{"label": "srv 3","selected": false}]},{"name": "area 4","services": [{"label": "srv 1","selected": true},{"label": "srv 2","selected": false},{"label": "srv 3","selected": true}]}]}

let final = data.areas.reduce((op, inp) => {
  let services = inp.services.filter( ({selected}) => selected )
  if(services.length) op.push({...inp, services})
  return op
},[])

console.log(final)

答案 6 :(得分:0)

您可以使用reducefilter内部数组,而无需更改输入

const input={"areas":[{"name":"area 1","services":[{"label":"srv 1","selected":true},{"label":"srv 2","selected":false},{"label":"srv 3","selected":false},{"label":"srv 4","selected":true}]},{"name":"area 2","services":[{"label":"srv 1","selected":false},{"label":"srv 2","selected":true},{"label":"srv 3","selected":false},{"label":"srv 4","selected":false}]},{"name":"area 3","services":[{"label":"srv 1","selected":false},{"label":"srv 2","selected":false},{"label":"srv 3","selected":false}]},{"name":"area 4","services":[{"label":"srv 1","selected":true},{"label":"srv 2","selected":false},{"label":"srv 3","selected":true}]}]}

const areas = input.areas.reduce((r, a) => {
  const services = a.services.filter(s => s.selected)
  
  if(services.length)
    r.push({ ...a, services });
    
  return r
}, [])

console.log({ areas })

答案 7 :(得分:0)

尝试这样的事情:

const data = {
  "areas": [{
      "name": "area 1",
      "services": [{
          "label": "srv 1",
          "selected": true
        },
        {
          "label": "srv 2",
          "selected": false
        },
        {
          "label": "srv 3",
          "selected": false
        },
        {
          "label": "srv 4",
          "selected": true
        }
      ]
    },
    {
      "name": "area 2",
      "services": [{
          "label": "srv 1",
          "selected": false
        },
        {
          "label": "srv 2",
          "selected": true
        },
        {
          "label": "srv 3",
          "selected": false
        },
        {
          "label": "srv 4",
          "selected": false
        }
      ]
    },
    {
      "name": "area 3",
      "services": [{
          "label": "srv 1",
          "selected": false
        },
        {
          "label": "srv 2",
          "selected": false
        },
        {
          "label": "srv 3",
          "selected": false
        }
      ]
    },
    {
      "name": "area 4",
      "services": [{
          "label": "srv 1",
          "selected": true
        },
        {
          "label": "srv 2",
          "selected": false
        },
        {
          "label": "srv 3",
          "selected": true
        }
      ]
    }
  ]
}

const res = data.areas.map(x => {
  // Destructure the name and services from the current callback object
  const { name, services } = x;

  // Now filter the services object where the .selected property is set to true
  const filteredServices = services.filter(x => x.selected);
  
  if (filteredServices.length) {
    // Project your desired object
    return { name: name, services: filteredServices }
  }
})
// Also filter for empty services
.filter(x => x);

console.log(res);

答案 8 :(得分:0)

您可以在过滤器的回调内部进行过滤,如下所示:

let data = {"areas": [{"name": "area 1", "services": [{"label": "srv 1", "selected": true}, {"label": "srv 2", "selected": false}, {"label": "srv 3", "selected": false}, {"label": "srv 4", "selected": true}]}, {"name": "area 2", "services": [{"label": "srv 1", "selected": false}, {"label": "srv 2", "selected": true}, {"label": "srv 3", "selected": false}, {"label": "srv 4", "selected": false}]}, {"name": "area 3", "services": [{"label": "srv 1", "selected": false}, {"label": "srv 2", "selected": false}, {"label": "srv 3", "selected": false}]}, {"name": "area 4", "services": [{"label": "srv 1", "selected": true}, {"label": "srv 2", "selected": false}, {"label": "srv 3", "selected": true}]}]};

const result = data.areas.filter(area => {
  // filter area services        
  let selectedServices = area.services.filter(service => {
    return service.selected;
  });

  // If the area has selected services
  if (selectedServices.length) {
    // Save the selected services to area.services
    area.services = selectedServices;
    return true;
  } else {
    // Do not select the area
    return false;
  }
});

console.log(result);

但是,如@CodeManiac所指出的,这将使原始数组发生突变,如果要保留它,则使用reducedata.areas.reduce()而不是data.areas.filter()

答案 9 :(得分:0)

在完成第一次过滤后,可以按以下步骤过滤每个索引中的服务:

result.forEach((item)=>{
     item.services = item.services.filter((service)=>service.selected==true);
})