10

I am really surprised I haven't been able to find anything related to my question. I am looking for a fast way to filter my array of objects based on a user text input.

Assume I have this array:

let data = [{
  "id": 1,
  "first_name": "Jean",
  "last_name": "Owens",
  "email": "[email protected]",
  "gender": "Female"
}, {
  "id": 2,
  "first_name": "Marie",
  "last_name": "Morris",
  "email": "[email protected]",
  "gender": "Female"
}, {
  "id": 3,
  "first_name": "Larry",
  "last_name": "Wallace",
  "email": "[email protected]",
  "gender": "Male"
}];

User writes "s", the expected result would be:

let result = [{
  "id": 1,
  "first_name": "Jean",
  "last_name": "Owens",
  "email": "[email protected]",
  "gender": "Female"
}, {
  "id": 2,
  "first_name": "Marie",
  "last_name": "Morris",
  "email": "[email protected]",
  "gender": "Female"
}]

I could use the filter function in such a way:

let = searchText = "s";
    let result = data.filter(object=>{
      for (var property in object) {
        if (object.hasOwnProperty(property)) {
          return object[property].toString().toLowerCase().indexOf(searchText) !== -1;
        }
      }
    });

So I am wondering if there are better alternatives to this solution?

--Here is a working JsFiddle thanks to KoolShams

--Plunker for benchmark purposes (tested with 2k data)

4
  • In this case a research with "l" will return you the whole data becouse "l" is part of either "male" or "female"...... Strange behavior Commented Oct 2, 2016 at 14:21
  • Yes? This is exactly what I want :) Commented Oct 2, 2016 at 14:24
  • 1
    Created a fiddle for you. jsfiddle.net/d8mhtjs5/5 Commented Oct 2, 2016 at 14:29
  • Thanks for the fiddle @KoolShams, I will add it to the question ! Commented Oct 2, 2016 at 14:34

3 Answers 3

8

You could use Object.keys() and some() instead.

let data = [{
  "id": 1,
  "first_name": "Jean",
  "last_name": "Owens",
  "email": "[email protected]",
  "gender": "Female"
}, {
  "id": 2,
  "first_name": "Marie",
  "last_name": "Morris",
  "email": "[email protected]",
  "gender": "Female"
}, {
  "id": 3,
  "first_name": "Larry",
  "last_name": "Wallace",
  "email": "[email protected]",
  "gender": "Male"
}];

var result = data.filter(function(o) {
  return Object.keys(o).some(function(k) {
    return o[k].toString().toLowerCase().indexOf('s') != -1;
  })
})

console.log(result)

Sign up to request clarification or add additional context in comments.

3 Comments

Nice, I like it, would the some function be faster than the loop ?
Not sure about that, if this is right way to test it it seems that loop is always faster jsfiddle.net/Lg0wyt9u/1253
I have tested with 2k data and a few different strings and the loop is definitely faster: plnkr.co/edit/i1it9PZ7WMzwpsopT7pS?p=preview
1

You could use Object.keys and omit hasOwnProperty.

This solution features arrow functions.

let data = [{ "id": 1, "first_name": "Jean", "last_name": "Owens", "email": "[email protected]", "gender": "Female" }, { "id": 2, "first_name": "Marie", "last_name": "Morris", "email": "[email protected]", "gender": "Female" }, { "id": 3, "first_name": "Larry", "last_name": "Wallace", "email": "[email protected]", "gender": "Male" }],
    searchText = "s",
    result = data.filter(o => 
        Object.keys(o).some(k => 
            o[k].toString().toLowerCase().indexOf(searchText) !== -1));

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

For a better performance, you could store the keys in advance and iterate the keys, without using Object.keys for all objects in the array, if they are uniform.

let data = [{ "id": 1, "first_name": "Jean", "last_name": "Owens", "email": "[email protected]", "gender": "Female" }, { "id": 2, "first_name": "Marie", "last_name": "Morris", "email": "[email protected]", "gender": "Female" }, { "id": 3, "first_name": "Larry", "last_name": "Wallace", "email": "[email protected]", "gender": "Male" }],
    keys = Object.keys(data[0]),
    searchText = "s",
    result = data.filter(o => 
        keys.some(k => 
            o[k].toString().toLowerCase().indexOf(searchText) !== -1));

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

1 Comment

I added your solution to my benchmark, which I've added to the question, the loop is still the fastest one.
1

Well, you can use any lodash's collection related function to object and it will iterate over values. Also you can use directly _.toLower to any string or number or Boolean and it will handle all the corner cases, so if you want a easier solution, and well structured code then here you go:

data.filter(o=>_.some(o, v => _.toLower(v).indexOf('s')>-1))

Here is the working example:

let data = [{
  "id": 1,
  "first_name": "Jean",
  "last_name": "Owens",
  "email": "[email protected]",
  "gender": "Female"
}, {
  "id": 2,
  "first_name": "Marie",
  "last_name": "Morris",
  "email": "[email protected]",
  "gender": "Female"
}, {
  "id": 3,
  "first_name": "Larry",
  "last_name": "Wallace",
  "email": "[email protected]",
  "gender": "Male"
}];

var sTxt = 's';

var res = data.filter(o=>_.some(o, v =>_.toLower(v).indexOf(sTxt)>-1))

console.log('Result: ', JSON.stringify(res,null,'    '));
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.js"></script>

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.