1

How can I filter my array of objects by property name and value?

For example, I have to filter objects if their property aa.town is Edinburgh

I need to filter using whatever object literal is passed as a parameter - I do not want to hardcode the value.

What I have tried so far is

export function objectFilter(people, 'aa.town', 'Edinburgh'); {
    return objects.filter(item => item[keysString] == searchString);
}

Here is a people array:

export const people = [
  {
    a: 'Jim',
    b: 'male',
    c: '1971',
    aa: {
      town: 'London',
    },
  },
  {
    a: 'Bob',
    b: 'male',
    c: '1971',
    aa: {
      town: 'Edinburgh',
    },
  },
Bomber
  • 10,195
  • 24
  • 90
  • 167

3 Answers3

1

Using Filter method

(updated answer)

function objectFilter(people, input) {
  return people.filter(item => "town" in item.aa && item.aa.town === input);
}

const people = [
  {
    a: "Jim",
    b: "male",
    c: "1971",
    aa: {
      town: "Edinburgh"
    }
  },

  {
    a: "Bob",
    b: "male",
    c: "1971",
    aa: {
      town: "London"
    }
  },
  {
    a: "Tom",
    b: "male",
    c: "1951",
    aa: {
      city: "Edinburgh"
    }
  }
];

function objectFilter(people, input) {
  return people.filter(item => "town" in item.aa && item.aa.town === input);
}

console.log(objectFilter(people, "Edinburgh"));
teddcp
  • 1,514
  • 2
  • 11
  • 25
  • I want to filter depending what string was passed as the parameter, rather than hardcode the value – Bomber Mar 23 '20 at 17:45
  • @Bomber, i hv updated the answer which is meeting the requirement of property and town 'Edinburgh' – teddcp Mar 23 '20 at 18:07
  • `aa.town` could be any value - I want to filter on what the parameter is, which could be any object literal. Not hardcode the value. – Bomber Mar 23 '20 at 18:35
  • @Bomber,Please re-write your question clearly.It would be helpful for me. – teddcp Mar 23 '20 at 18:41
0

To get the object value obj.aa.town from string "aa.town" We can use reduce function like this

nestedProp.split('.').reduce((a,b)=>a[b], item)

function objectFilter(objects, nestedProp, propValue){
return objects.filter(item =>        nestedProp.split('.').reduce((a,b)=>a[b], item) == propValue);
}
const people = [
  {
    a: 'Jim',
    b: 'male',
    c: '1971',
    aa: {
      town: 'London',
    },
  },
  {
    a: 'Bob',
    b: 'male',
    c: '1971',
    aa: {
      town: 'Edinburgh',
    },
  }
];  
console.log(objectFilter(people, 'aa.town', 'Edinburgh'));
.as-console-wrapper { max-height: 100% !important; top: 0; }
M A Salman
  • 3,666
  • 2
  • 12
  • 26
0

I hope this could speed up and applicable to what you wants.

Edit: I have test this matter. This is free of trees depth limitation and have good performance impact.

/* set mode = 0 for root object retval,
   set mode = 1 for first object retval,
   otherwise for last object retval

   eg. mode2 : for key = "aa.town" and value = "Edinburgh" will return { town: "Edinburgh" }, and so on.
   eg. mode1 : for key = "bb.gen.OO7" and value = "Gen 7" will return { bb: { gen: { OO7: "Gen 7" } } }, and so on.
*/
export function getObject(array, key, value, mode = 1) {
    if (typeof key !== "string" || key.trim() === "") return;

    const gen7 = (_a, _key) => { return _a[_key] };

    const getItem= (_object, _keys) => {
        let i = 0, n = _keys.length-1, stack = _object;
        while (i < n && (stack = gen7(stack, _keys[i++])) !== undefined);
        return stack;
    };

    let keys = key.split("."),
        first = keys[0],
        last = keys[keys.length-1],
        i = 0, len = array.length, obj;

    while (i < len && ((obj = getItem(array[i], keys)) === undefined || obj[last] !== value)) i++;

    if (i < len) return mode === 0 ? array[i] : mode === 1 ? array[i][first] : obj;
}

const people = [
{
    a: 'Jim',
    b: 'male',
    c: '1971',
    aa: {
        town: 'London',
    },
    bb: {
        gen: {
            OO7: 'Gen 7'
        }
    }
},
{
    a: 'Bob',
    b: 'male',
    c: '1971',
    aa: {
        town: 'Edinburgh',
    },
  }
]; 
OO7
  • 660
  • 4
  • 10