首页 > 解决方案 > 如何使用对象数组过滤数组对象

问题描述

我有一个像这样的过滤组js对象:

 let filter = {
generalFilter:[
    {key: "connected", value: true},
    {key: "connected", value: false}
],
locationFilter:[
    {key: "deviceLocation", value: "def"},
     {key: "deviceLocation", value: "abc"}
],
paymentMethodsFilter:[
    {key: "devicePaymentMethods", value: "ab"}
]

}

和这样的主数组:

const devices = [{
    deviceLocation: {
      label: "abc",
      value: "abc"
    },
    deviceName: "test7",
    devicePaymentMethods: [{
      label: "ab",
      value: "ab"
    }, {
      label: "cd",
      value: "cd"
    }, {
      label: "ef",
      value: "ef"
    }],
    deviceType: "iPad",
    id: "001",
    connected: true,
    enabled: true,
  },
  {
    deviceLocation: {
      label: "def",
      value: "def"
    },
    deviceName: "test4",
    devicePaymentMethods: [{
      label: "ab",
      value: "ab"
    }, {
      label: "cd",
      value: "cd"
    }],
    deviceType: "iPad",
    id: "004",
    connected: false,
    enabled: false,
  }
];

如何使用过滤器对象过滤此设备数组?这是我尝试过的,但它不起作用

devices.filter((device) => {
    let shouldKeep = new Array(3)
    shouldKeep.fill(0) //fills the array with 0, meaning no filter groups has passed yet
    for(let filterGroupIndex in filter) {// Loop through each filter group in filter
        let filterGroup = filter[filterGroupIndex]
        for(let filterObject in filterGroup) { //Loop through
            if(filterGroup[filterObject].key in device && device[filterGroup[filterObject].key] === filterGroup[filterObject].value) {
                shouldKeep[filterGroupIndex] = 1 //Set current filterGroup to 1, meaning it has passed the filter
                break; // At least one value in that filter group is true, skip to next filter group
            }
        }
    }

    if(shouldKeep.reduce((a,b) => a + b, 0) >= filter.length) {
        return true;
    }
    return false
})

有时这个过滤器对象可能是空的,当它为空时它应该返回完整的数组而不过滤主数组。这样做的最佳方法是什么?我不确定这也许有另一种解决方案。请帮我

默认过滤器对象是这样的

let filter = {
    generalFilter:[],
    locationFilter:[],
    paymentMethodsFilter:[]

    }

例如,用户可以将对象添加到我正在使用反应挂钩的过滤器数组

 let filter = {
generalFilter:[
    {key: "connected", value: true},
    {key: "connected", value: false}
],
locationFilter:[],
        paymentMethodsFilter:[]}

然后我们必须检查两个 connected: false 和 connected: true 匹配主数组中的数据(如果数据已连接:主数组中的 true 则它会显示,如果数据已连接:false 它会显示)

对于这种类型的过滤器

let filter = {
generalFilter:[
    {key: "connected", value: true},
    {key: "connected", value: false}
],
locationFilter:[
    {key: "deviceLocation", value: "def"},
     {key: "deviceLocation", value: "abc"}
],
paymentMethodsFilter:[
    {key: "devicePaymentMethods", value: "ab"}
]

}

结果应该是

result =[{
    deviceLocation: {
      label: "abc",
      value: "abc"
    },
    deviceName: "test7",
    devicePaymentMethods: [{
      label: "ab",
      value: "ab"
    }, {
      label: "cd",
      value: "cd"
    }, {
      label: "ef",
      value: "ef"
    }],
    deviceType: "iPad",
    id: "001",
    connected: true,
    enabled: true,
  },
  {
    deviceLocation: {
      label: "def",
      value: "def"
    },
    deviceName: "test4",
    devicePaymentMethods: [{
      label: "ab",
      value: "ab"
    }, {
      label: "cd",
      value: "cd"
    }],
    deviceType: "iPad",
    id: "004",
    connected: false,
    enabled: false,
  }
];

因为你可以在过滤器中看到 connected:true 和 connected :false 和 deviceLocation 与 def 和 abc 以及 devicePaymentMethods 是 ab

这意味着我希望所有连接 true 和连接 false 的设备与位置 abc 和 def 和 paymetmethod ab

标签: javascriptreactjsfilter

解决方案


检查评论以获取解释。

const filter = {
    generalFilter: [
        {key: "connected", value: true},
        {key: "connected", value: false}
    ],
    locationFilter: [
        {key: "deviceLocation", value: "def"},
        {key: "deviceLocation", value: "abc"}
    ],
    paymentMethodsFilter: [
        {key: "devicePaymentMethods", value: "ab"}
    ]
};

const parsedFilter = {};

/**
  converting filter into a hashmap with a filter as a Key and value as an 
  array of possible values.
  
  parsedFilter looks like this
 {"connected":[true,false],"deviceLocation":["def","abc"],"paymentOption":["ab"]}

  now we can easily check if any value is present in the filter.

   **/
const filterKeys = Object.keys(filter);

filterKeys.forEach((filterKey) => {
    if (Array.isArray(filter[filterKey])) {
        filter[filterKey].forEach((filterItem) => {
            if (Object.prototype.hasOwnProperty.call(parsedFilter, filterItem.key)) {
                parsedFilter[filterItem.key].push(filterItem.value);
            } else {
                parsedFilter[filterItem.key] = [filterItem.value];
            }
        });
    }
});


const devices = [
    {
        deviceLocation: {
            label: "abc",
            value: "abc"
        },
        deviceName: "test7",
        devicePaymentMethods: [
            {
                label: "ab",
                value: "ab"
            }, {
                label: "cd",
                value: "cd"
            }, {
                label: "ef",
                value: "ef"
            }],
        deviceType: "iPad",
        id: "001",
        connected: true,
        enabled: true,
    }
];

const result = [];

/**
  Looping through each device and check if that key is present in the 
  parsedFilter.
  
  if true: check for typeof value for that device key.
           if Object: then check if it is present in the array of not for the 
                      givem deviceKey in parsedFilter.
           if Array: then loop through each item and check if it is present 
                     in the parsedFilter for the given deviceKey
           if Number, string, boolean: Check if is present in the 
                      parsedFilter for the given deviceKey

  if false: simply add it to the result.
**/
if (Array.isArray(devices)) {
    devices.forEach((device) => {
        const keys = Object.keys(device);
        const resultDeviceObj = {};

        keys.forEach((key) => {
            if (Object.prototype.hasOwnProperty.call(parsedFilter, key)) {
                if (typeof device[key] === "object" && parsedFilter[key].includes(device[key].value)) {
                    resultDeviceObj[key] = device[key];
                } else if (Array.isArray(device[key])) {
                    const arrayResult = [];

                    device[key].forEach((item) => {
                        if (parsedFilter[key].includes(item.value)) {
                            arrayResult.push(item);
                        }
                    });

                    resultDeviceObj[key] = arrayResult;
                } else if(parsedFilter[key].includes(device[key])) {
                    resultDeviceObj[key] = device[key];
                }
            } else {
                resultDeviceObj[key] = device[key];
            }
        });

        result.push(resultDeviceObj);
    });
}

console.log("result", result);

编辑

const filter = {
    generalFilter: [{key: "connected", value: true}],
    locationFilter: [{key: "deviceLocation", value: "abcd"}],
    paymentMethodsFilter: [{key: "devicePaymentMethods", value: "ab"}]
};

const parsedFilter = {};

const filterKeys = Object.keys(filter);

filterKeys.forEach((filterKey) => {
    if (Array.isArray(filter[filterKey])) {
        filter[filterKey].forEach((filterItem) => {
            if (Object.prototype.hasOwnProperty.call(parsedFilter, filterItem.key)) {
                parsedFilter[filterItem.key][filterItem.value] = filterItem.value;
            } else {
                parsedFilter[filterItem.key] = {
                    [filterItem.value]: filterItem.value
                }
            }
        });
    }
});

//{"connected":{"true": true,"false": "false"},"deviceLocation":{"def": "def","abc": "abc"},"paymentOption":{"ab": "ab"}}
const devices = [{
    deviceLocation: {
        label: "abc",
        value: "abc"
    },
    deviceName: "test7",
    devicePaymentMethods: [{
        label: "ab",
        value: "ab"
    }, {
        label: "cd",
        value: "cd"
    }, {
        label: "ef",
        value: "ef"
    }],
    deviceType: "iPad",
    id: "001",
    connected: true,
    enabled: true,
},
    {
        deviceLocation: {
            label: "def",
            value: "def"
        },
        deviceName: "test4",
        devicePaymentMethods: [{
            label: "ab",
            value: "ab"
        }, {
            label: "cd",
            value: "cd"
        }],
        deviceType: "iPad",
        id: "004",
        connected: false,
        enabled: false,
    }
];

const result = [];

const isObject = function (a) {
    return a.constructor.toString().indexOf("Object") !== -1;
};

if (Array.isArray(devices)) {
    devices.forEach((device) => {
            const keys = Object.keys(device);
            let isValid = true;
            for (let i = 0; i < keys.length; i++) {
                const key = keys[i];

                if (Object.prototype.hasOwnProperty.call(parsedFilter, key)) {
                    if (isObject(device[key]) &&
                        !Object.prototype.hasOwnProperty.call(parsedFilter[key], device[key].value)) {
                        isValid = false;
                        break;
                    } else if (Array.isArray(device[key])) {
                        isValid = false;
                        for (let j = 0; j < device[key].length; j++) {
                            const item = device[key][j];
                            if (Object.prototype.hasOwnProperty.call(parsedFilter[key], item.value)) {
                                isValid = true;
                                break;
                            }
                        }

                        if (!isValid) {
                            break;
                        }
                    } else if (typeof device[key] === "boolean" &&
                        !Object.prototype.hasOwnProperty.call(parsedFilter[key], device[key])) {
                        isValid = false;
                        break;
                    }
                }
            }

            if (isValid) {
                result.push(device);
            }
        }
    );
}


console.log("result", result)


推荐阅读