简体   繁体   中英

Loop through array of arrays to find a countrys neighbors

I have the following structure in my JavaScript:

var map_neighbour_regions = [{
    "id": 1,
    "name": "Alaska",
    "dom_element": "Alaska",
    "continent_id": 1,
    "neighbours": [{
        "id": 1,
        "region_id": 1,
        "neighbour_region_id": 59
    }, {
        "id": 2,
        "region_id": 1,
        "neighbour_region_id": 64
    }]
}, {
    "id": 2,
    "name": "Algeria",
    "dom_element": "Algeria",
    "continent_id": 1,
    "neighbours": [{
        "id": 3,
        "region_id": 2,
        "neighbour_region_id": 10
    }, {
        "id": 4,
        "region_id": 2,
        "neighbour_region_id": 19
    }, {
        "id": 5,
        "region_id": 2,
        "neighbour_region_id": 47
    }, {
        "id": 6,
        "region_id": 2,
        "neighbour_region_id": 52
    }],
    .....
}

In a loop, I want to find a given country, then access each neighbour country. I am not able to get this working.

I start with a country name, I want to find it in the list of first countries, then for each neighbour id get the name again from the first list.

I want to end up with (for example) an array of region names which are neighbours to the input country name. For an input country such as Argentine, I want to output:

neighbour_regions = {'chile', 'brazil', 'bolivia'};

I have tried without success (undefined) just to access the first level:

function highlightNeighbouringRegions(country) {

    console.log(map_neighbour_regions [0][country]);

    console.log(map_neighbour_regions [0].country);

    console.log(map_neighbour_regions [country]);

};

I have added a JSFiddle here .

I like dynamic solutions.

Here is a recursive function which requires :

  • The prop name that you want to compare (" name in your example")
  • The desiredValue value that you want to compare to (" Argentina in your example")

So :

function findNode(prop, desiredValue, jsonObj)
    {
        if (!jsonObj || "object" !== typeof jsonObj) { return; }
        if (jsonObj[prop] === desiredValue) { return jsonObj; }
        for (var x in jsonObj)
        {
            if (Object.hasOwnProperty.call(jsonObj, x))
            {
                var result = findNode(prop, desiredValue, jsonObj[x]);
                if (result !== undefined) { return result; }
            }
        }
    }

And now you can do :

var a=findNode("name","Argentina",map_region_neighbours); 
console.table(a.neighbours); //check for undefined etc...

Result :

在此处输入图片说明

http://jsfiddle.net/5tfnxwkw/2/

Edit:

After your comment , I enhanced the function.

Now the function takes Assertion

The assertion will check for condition/property to be present.

For example :

{
    "id": 4,
    "name": "Argentina",
    "dom_element": "Argentina",
    "continent_id": 1,
    "neighbours": [{
        "id": 9,
        "region_id": 4,
        "neighbour_region_id": 8
    }
...

Let's look at id : to which ID I'm referring ? the inner or outsider ?

So now the method looks like :

function findNode(prop, desiredValue, jsonObj,assertion)

So now if I supply :

findNode("id", ..., ...,'dom_element')

It will ALSO SEARCH FOR a sibling called dom_element

So this will match "id": 4, .

So if your name is John and you have a brother named Paul , and you have also a son called John which has a brother named Ringo , so if I want to refer you - the trick here is to search "John" which has "Paul" sibling. ( and not ringo)

Ok but What if I want the inner id? "id": 9,

Then - You will call the method like :

findNode("id", ..., ...,'region_id')

So you actually help the method decide which node to chose.

OK so how the final code will look ?

var n=findNode("name","Alaska",map_region_neighbours,'name').neighbours;

n.forEach(function logArrayElements(element, index, array) {
    console.log("******neighboors  id  "+(element["id"])+"  has a name of : ");
    console.log( findNode("id", element["id"], map_region_neighbours,'dom_element').name);
}) 

Result :

******neighboors  id  1  has a name of : 
Alaska
******neighboors  id  2  has a name of : 
Algeria

New jsbin : http://jsfiddle.net/5tfnxwkw/3/

Following code will show you in the console all neighbours of country name, that you have passed as a variable to the function highlightNeighbouringRegions :

function highlightNeighbouringRegions(country) {
    var result = [];

    $.each(map_neighbour_regions, function(idx1, e1) {
        if (e1.name === country) {
            var neighbour_regions = [];

            $.each(e1.neighbours, function(idx2, e2) {
                neighbour_regions.push(e2.neighbour_region_id);
            });

            $.each(map_neighbour_regions, function(idx3, e3) {
                if ($.inArray(e3.id, neighbour_regions) > -1) {
                    result.push(e3.name);
                }
            });
        }
    });

    return result;
}

var neighbour_regions = highlightNeighbouringRegions('Alaska');

console.log(neighbour_regions);

This code will return you desired data - in neighbour_regions you will have an array with all neighbours country names.

DEMO

I want to end up with (for example) an array of region names which are neighbours to the input country name. For an input country such as Argentine, I want to output:

neighbour_regions = {'chile', 'brazil', 'bolivia'};

Here is another way:

function getNeighbors(search) {
    var found = regions.filter(function(s) { // filter regions for search term
        return s.name == search;
    })[0].neighbours.map(function(n) { // create array of ids from found items
        return n.id;
    });
    // create and return an array of name from regions where id matches
    return regions.reduce(function(result, r) { 
        if (found.indexOf(r.id) > -1) result.push(r.name);
        return result;
    }, []);
}

Calling this function as getNeighbors('Alaska') will get you an array of neighbour names ["Algeria", "Antartica"] .

Demo Fiddle : http://jsfiddle.net/abhitalks/zpgfjuc0/

Demo Snippet :

 var regions = [{ "id": 1, "name": "Alaska", "dom_element": "Alaska", "continent_id": 1, "neighbours": [{ "id": 2, "region_id": 1, "neighbour_region_id": 59 }, { "id": 3, "region_id": 1, "neighbour_region_id": 64 }] }, { "id": 2, "name": "Algeria", "dom_element": "Algeria", "continent_id": 1, "neighbours": [{ "id": 1, "region_id": 2, "neighbour_region_id": 10 }, { "id": 4, "region_id": 2, "neighbour_region_id": 19 }] }, { "id": 3, "name": "Antartica", "dom_element": "AntarticWildlifeTerritory", "continent_id": 1, "neighbours": [{ "id": 1, "region_id": 3, "neighbour_region_id": 5 }, { "id": 8, "region_id": 3, "neighbour_region_id": 49 }] }, { "id": 4, "name": "Argentina", "dom_element": "Argentina", "continent_id": 1, "neighbours": [{ "id": 2, "region_id": 4, "neighbour_region_id": 8 }, { "id": 10, "region_id": 4, "neighbour_region_id": 9 }, { "id": 11, "region_id": 4, "neighbour_region_id": 12 }, { "id": 12, "region_id": 4, "neighbour_region_id": 50 }] }]; function getNeighbors(country) { var found = regions.filter(function(c) { return c.name == country; })[0].neighbours.map(function(n) { return n.id; }); return regions.reduce(function(result, r) { if (found.indexOf(r.id) > -1) result.push(r.name); return result; }, []); } snippet.log(getNeighbors('Alaska')); snippet.log(getNeighbors('Algeria')); snippet.log(getNeighbors('Argentina')); 
 <script src="http://tjcrowder.github.io/simple-snippets-console/snippet.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