TheRealPapa
TheRealPapa

Reputation: 4539

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.

Upvotes: 2

Views: 268

Answers (3)

Royi Namir
Royi Namir

Reputation: 148574

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 :

enter image description here

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/

Upvotes: 3

Abhitalks
Abhitalks

Reputation: 28397

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>

Upvotes: 0

Legionar
Legionar

Reputation: 7597

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

Upvotes: 0

Related Questions