82

I need to search inside a json list of countries. The json is like:

[ 
{"name": "Afghanistan", "code": "AF"}, 
{"name": "Åland Islands", "code": "AX"}, 
{"name": "Albania", "code": "AL"}, 
{"name": "Algeria", "code": "DZ"}
]

I get from database only the code and would output the entire name. So if I get "AL" I would like to retrieve from json "Albania"

Penny Liu
  • 15,447
  • 5
  • 79
  • 98
Tropicalista
  • 3,097
  • 12
  • 44
  • 72

5 Answers5

142

I suggest using JavaScript's Array method filter() to identify an element by value. It filters data by using a "function to test each element of the array. Return true to keep the element, false otherwise.."

The following function filters the data, returning data for which the callback returns true, i.e. where data.code equals the requested country code.

function getCountryByCode(code) {
  return data.filter(
      function(data){ return data.code == code }
  );
}

var found = getCountryByCode('DZ');

See the demonstration below:

var data = [{
  "name": "Afghanistan",
  "code": "AF"
}, {
  "name": "Åland Islands",
  "code": "AX"
}, {
  "name": "Albania",
  "code": "AL"
}, {
  "name": "Algeria",
  "code": "DZ"
}];


function getCountryByCode(code) {
  return data.filter(
    function(data) {
      return data.code == code
    }
  );
}

var found = getCountryByCode('DZ');

document.getElementById('output').innerHTML = found[0].name;
<div id="output"></div>

Here's a JSFiddle.

showdev
  • 28,454
  • 37
  • 55
  • 73
  • 2
    I know this is answer is over 5 years old, but the statement that it return "only the value for which the callback returns true" is incorrect. It returns an **array** of **objects** where the value in each matched object causes the callback to return true. Your code does recognise this, but I feel the statement is misleading – freefaller Apr 04 '19 at 14:42
85
var obj = [
  {"name": "Afghanistan", "code": "AF"}, 
  {"name": "Åland Islands", "code": "AX"}, 
  {"name": "Albania", "code": "AL"}, 
  {"name": "Algeria", "code": "DZ"}
];

// the code you're looking for
var needle = 'AL';

// iterate over each element in the array
for (var i = 0; i < obj.length; i++){
  // look for the entry with a matching `code` value
  if (obj[i].code == needle){
     // we found it
    // obj[i].name is the matched result
  }
}
Brad Christie
  • 100,477
  • 16
  • 156
  • 200
  • As I stated, it is correct. But just try imagine this list with 100.000 items. – ivoszz Oct 08 '13 at 17:13
  • 4
    @Tropicalista In fact, you should move the filter logic to your database engine! The DB will always be the fastest when it comes to filtering, ordering or grouping (assuming you set correct indices). – ComFreek Oct 08 '13 at 17:14
  • @ivoszz: Except that [`Array.forEach`](http://stackoverflow.com/questions/156696/which-web-browsers-natively-support-array-foreach) can be temperamental when it comes to compatibility. – Brad Christie Oct 08 '13 at 17:21
  • 2
    It's missing a coma: for (var i = 0; i < obj.length **;** i++){ – Aline Matos Oct 13 '15 at 13:54
  • Could use find, filter in a loop rather! – jaibalaji Jul 17 '20 at 18:09
  • 1
    @jaibalaji not if you support IE. Also keep in mind this post is now going on 5 years old, [compatibility](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find#Browser_compatibility) has changed. – Brad Christie Jul 17 '20 at 18:15
60

Just use the ES6 find() function in a functional way:

var data=[{name:"Afghanistan",code:"AF"},{name:"Åland Islands",code:"AX"},{name:"Albania",code:"AL"},{name:"Algeria",code:"DZ"}];

let country = data.find(el => el.code === "AL");
// => {name: "Albania", code: "AL"}
console.log(country["name"]);

or Lodash _.find:

var data=[{name:"Afghanistan",code:"AF"},{name:"Åland Islands",code:"AX"},{name:"Albania",code:"AL"},{name:"Algeria",code:"DZ"}];

let country = _.find(data, ["code", "AL"]);
// => {name: "Albania", code: "AL"}
console.log(country["name"]);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>
xinthose
  • 3,213
  • 3
  • 40
  • 59
Penny Liu
  • 15,447
  • 5
  • 79
  • 98
20

First convert this structure to a "dictionary" object:

dict = {}
json.forEach(function(x) {
    dict[x.code] = x.name
})

and then simply

countryName = dict[countryCode]

For a list of countries this doesn't matter much, but for larger lists this method guarantees the instant lookup, while the naive searching will depend on the list size.

georg
  • 211,518
  • 52
  • 313
  • 390
  • um? countryName = dict[code], surely? or am I missing something? – twobob May 05 '17 at 11:19
  • I'm not at all sure it's true that _"this method guarantees the instant lookup"_. Is there any guarantee that the implementation does anything but a sequential lookup? If not, can we be certain that no significant browser implementation does a sequential lookup? – Auspex Jul 11 '17 at 09:41
  • @Auspex This answer is relevant to your question https://stackoverflow.com/a/28225058/363217 – Purefan Oct 04 '17 at 13:03
13

Making more general the @showdev answer.

var getObjectByValue = function (array, key, value) {
    return array.filter(function (object) {
        return object[key] === value;
    });
};

Example:

getObjectByValue(data, "code", "DZ" );
Penny Liu
  • 15,447
  • 5
  • 79
  • 98
Osvaldo Cabrera
  • 327
  • 4
  • 4