简体   繁体   中英

How to get a single property of all children in a nested object using javascript?

For an interactive map which shows countries' data over time (using d3), I have a single large object called dataset . The properties of dataset are again objects identified by a country's name. The next level are objects, again, indicated by the year. The last level finally is the data to be displayed. The structure is something like this:

dataset
    - CountryA
        - 2010
            - population: 4000000
            - crime rate: 17.4
            - GDP per capita: 2800
        - 2011 
            - population: 4100000
            - crime rate: 16.8
            - GDP per capita: 2900
        - ...
    - CountryB
        - 2010
            - population: 3700000
            - crime rate: 25.6
            - GDP per capita: 1200
        - 2011 
            - population: 3850000
            - crime rate: 27.2
            - GDP per capita: 1180
        - ...
    - ...

Now, for updating the map, I need to find the range for a specific property in order to adapt the color range I want to use. For example, if I want to get the minimum and maximum values for crime rates in the year 2010, is there an easy command to retrieve that information?

I do have a list of all available countries and can of course loop through that list and get the value for specified year, compare it to a global min/max value and change it if necessary (using Math.min/max ). I am just wondering, if I there is an easy way to that, like

var crimeRateLow = getGlobalMin(dataset, 2, "crime rate");

// magic function
function getGlobalMin(object, unspecifiedLevels, indicator) { ... }

I am currently using the following function with j being the indicator and the year is a globally set variable:

function getRange(j) {
  var jRange = {"min": 0, "max": 0};
  for (k in dataset) {
    jRange["min"] = Math.min(jRange["min"], dataset[k][year][j]);
    jRange["max"] = Math.max(jRange["max"], dataset[k][year][j]);
  }
  return jRange;
}

Although there is no built-in function in d3 addressing your problem, d3 might help to solve it elegantly.

  1. De-nest your nested object into smaller arrays containing the field values of interest by repeatedly applying d3.values() to get an array of property values (still objects) of the associative array. These property values/objects are afterwards mapped to arrays containing just the field values of interest.

  2. Merge these arrays using d3.merge() into one large array.

  3. Apply d3.extent() to obtain the global extent (ie array [min,max ]) from it.

     function getGlobalExtent(data, field) { return d3.extent( // (3.) Get the global extent. d3.merge( // (2.) Merge all arrays into a single one. d3.values(data) // (1.) Array of all country objects in dataset .map(function(country) { // (1.) Map each country to array of field values for all years within. return d3.values(country) // (1.) Array of years in each country .map(function(year) { // (1.) Map each year to the requested field value. return year[field]; }); }) ) ); } 

I put together a working snippet:

 var dataset = { "CountryA": { "2010": { "population": 4000000, "crime rate": 17.4, "GDP per capita": 2800 }, "2011": { "population": 4100000, "crime rate": 16.8, "GDP per capita": 2900 } }, "CountryB": { "2010": { "population": 3700000, "crime rate": 25.6, "GDP per capita": 1200 }, "2011": { "population": 3850000, "crime rate": 27.2, "GDP per capita": 1180 } } }; function getGlobalExtent(data, field) { return d3.extent( // (3.) Get the global extent. d3.merge( // (2.) Merge all arrays into a single one. d3.values(data) // (1.) Array of all country objects in dataset .map(function(country) { // (1.) Map each country to array of field values for all years within. return d3.values(country) // (1.) Array of years in each country .map(function(year) { // (1.) Map each year to the requested field value. return year[field]; }); }) ) ); } // population: 3700000,4100000 //console.log("population:", getGlobalExtent(dataset, "population").join()); // crime rate: 16.8,27.2 //console.log("crime rate:", getGlobalExtent(dataset, "crime rate").join()); // GDP per capita: 1180,2900 //console.log("GDP per capita:", getGlobalExtent(dataset, "GDP per capita").join()); 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script> 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM