2

I have a json array of about 30 objects. Here's a sample object from the array:

{
    "id": 0,
    "name": "Valle",
    "activities": "night-life",
    "food": "fancy-food",
    "sport" : "baseball",
    "geoProfile": "artsy",
    "priority": 2
}

I am building out another object on a page based on user input. The user will choose between radio buttons and after they have made their choices, I will have an object such as:

{geoProfile: "artsy", activities: "nature", food: "fancy-food", sport: "cricket"}

I am using jQuery's $.each() method to go through each object as follows:

$.each(self.data(), function (i, s) {
    if (s.geoProfile == self.prefLocation() &&
        s.activities == self.prefActivity() &&
        s.food == self.prefFood() &&
        s.sport == self.prefSport()) {
        optionMatched = s;
        return false;
    }
});

This will return an object that has all four matches, but how can I return the json object that has the most matches to the user-built object? If two match, I want to then look at the "priority" property and return the one with the lowest priority.

2
  • For starters, you'll need to iterate through your array and compare their values to what the user entered. What have you tried so far? Commented Jul 15, 2016 at 21:30
  • @MikeC see edits above, thanks for responding Commented Jul 15, 2016 at 21:35

2 Answers 2

3

You could use Array#map and build a new array with the sum of the matched properties.

Later you can sort with map and use the result for sorting and get the first element.

var data = [/* your data here */],
    search = { geoProfile: "artsy", activities: "nature", food: "fancy-food", sport: "cricket" },
    result = data.map(function (a, i) {
        return {
            count: Object.keys(search).reduce(function (r, k) { return r + +(a[k] === search[k]); }, 0),
            priority: a.priority,
            index: i
        }
    });

result.sort(function (a, b) {
    return b.count - a.count || a.priority - b.priority;
});

A single loop solution

var data = [/* your data here */],
    search = { geoProfile: "artsy", activities: "nature", food: "fancy-food", sport: "cricket" },
    result = data.reduce(function (r, a, i) {
        document.write('<pre>' + JSON.stringify(r, 0, 4) + '</pre><hr>');
        var o = {
            count: Object.keys(search).reduce(function (q, k) { return q + +(a[k] === search[k]); }, 0),
            priority: a.priority,
            index: i
        };
        if (!i || o.count > r[0].count || o.count === r[0].count && o.priority < r[0].priority) {
            return [o];
        }
        o.count === r[0].count && o.priority === r[0].priority && r.push(o);
        return r;
    }, []);
Sign up to request clarification or add additional context in comments.

11 Comments

Thanks for the response. I think I understand. So in your example, 'data' would be my json objects and 'search' would be the object that gets built by the user?
right. the data keeps the array with the objects you have and search is the wanted part to look for.
Does this take the priority value into account?
@MikeC, i do not understand this part.
"If two match, I want to then look at the "priority" property and return the one with the lowest priority"
|
0

Just track the number of matches and update your selected one based on if it has more matches.

var numOfMatches = 0;
$.each(self.data(), function(i, s) {
  var matchingProperties = 0;
  if (s.geoProfile == self.prefLocation()) {
    matchingProperties++;
  }
  if (s.activities == self.prefActivity()) {
    matchingProperties++;
  }
  if (s.food == self.prefFood()) {
    matchingProperties++;
  }
  if (s.sport == self.prefSport()) {
    matchingProperties++;
  }

  if (matchingProperties === 0 || matchingProperties < numOfMatches) {
    return;
  }

  if (!optionMatched // Grab the first match
      || matchingProperties > numOfMatches // or if more properties match
      || s.priority < optionMatched.priority) { // or the one with a lower priority
    optionMatched = s;
    numOfMatches = matchingProperties;
  }
});

Or you could simplify the initial counting using filter:

var numOfMatches = 0;
$.each(self.data(), function(i, s) {
  var matchingProperties = [
    s.geoProfile == self.prefLocation(),
    s.activities == self.prefActivity(),
    s.food == self.prefFood(),
    s.sport == self.prefSport()
  ].filter(function(val) { return val; }).length;

  if (matchingProperties === 0 || matchingProperties < numOfMatches) {
    return;
  }

  if (!optionMatched // Grab the first match
      || matchingProperties > numOfMatches // or if more properties match
      || s.priority < optionMatched.priority) { // or the one with a lower priority
    optionMatched = s;
    numOfMatches = matchingProperties;
  }
});

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.