1

I have a product that looks like this:

{
    "productId": 5256502,
    "name": "360fly - 4K Action Camera",
    "light": true,
    "wiFi": true,
    "colour": "Black"
}

and I have some criteria that looks like this:

_criteria = [
    {
        "id": 38,
        "type": "Boolean",
        "name": "Light",
        "states": [
            {
                "id": 93,
                "criteriaId": 38,
                "name": "False"
            },
            {
                "id": 94,
                "criteriaId": 38,
                "name": "True"
            }
        ]
    },
    {
        "id": 41,
        "type": "Boolean",
        "name": "New",
        "states": [
            {
                "id": 95,
                "criteriaId": 41,
                "name": "True"
            },
            {
                "id": 96,
                "criteriaId": 41,
                "name": "False"
            }
        ]
    },
    {
        "id": 42,
        "type": "Boolean",
        "name": "Available",
        "states": [
            {
                "id": 97,
                "criteriaId": 42,
                "name": "True"
            },
            {
                "id": 98,
                "criteriaId": 42,
                "name": "False"
            }
        ]
    }
];

Criteria maps to a product by name. So for example, if I have a criteria called Light then I will should have a corresponding field called light in a product. So, I am trying to build a function that checks that out.

I was trying to loop through all the product properties like this:

// For each property in our product
for (var property in product) {

    // If we have a property and it doesn't start with an underscore
    if (product.hasOwnProperty(property) && property.substring(0, 1) !== '_' && property !== 'productId' && property !== 'name') {


    }
}

and then I was going to loop through the criteria and match the name (after converting it to camelCase). But I need to compare it the other way around too, so I have to loop through all criteria and see if any exist in that that don't exist on a product.

I am hoping there is a nicer way of doing this than loop through all products, then looping through all criteria and matching and once that is done, loop through all criteria and then loop through all products.

Does anyone know of a way to help me out?

r3plica
  • 13,017
  • 23
  • 128
  • 290

2 Answers2

0

You could go down the approach of nesting a couple of for loops and removing matched elements from both of the arrays for the next iteration. This would reduce the amount of overhead as the array would get smaller for each iteration.

Using Monkey-Patching, we can make sure that the property elements are read as being lowercase:

Object.prototype.hasOwnPropertyCI = function(prop) {
   return Object.keys(this)
          .filter(function (v) {
             return v.toLowerCase() === prop.toLowerCase();
           }).length > 0;
};

Next iterate through both arrays and splice where required. After these nested for loops iterate, both arrays should only contain elements that don't match in the other one.

for(var i = 0; i < _criteria.length; i++){
  for(var j = 0; j < product.length; j++){
     if(product[j].hasOwnProperty(_criteria[i].name.toLowerCase())){
        product.splice(j,1);
        _criteria.splice(i,1);
        j--;
        i--;
     }
  }
}

Here is a fiddle: https://jsfiddle.net/p1c4kdhv/1/

Essentially what I am doing here is reducing the sample size every time a match is found. Thus, a smaller number of comparisons would be required for the next iteration which can improve efficiency.

Note that this central approach can be modified if there are multiple comparisons of a specific property type. Just modify where in the loops the arrays get spliced and the decrements happen.

Community
  • 1
  • 1
A.Sharma
  • 2,771
  • 1
  • 11
  • 24
0

It is a little unclear of what you are asking. But I think you are asking to see which criteria the product meets. This snippet will return an array of criteria names that are true within the product.

let output = [];

_criteria.forEach(item => {
  const {name} = item;
  output = output.concat(Object.keys(product).filter(key => {
    return product[key] === true && key.toLowerCase() === name.toLowerCase();
  }));
});

// returns ['light'] using your test data because only light is true and is in the criteria list

and here is an example http://jsbin.com/wobuhiteja/edit?js,console

pizzarob
  • 11,711
  • 6
  • 48
  • 69