javascript: get index of object from dictonary key - javascript

my data array
data : [
{
"name": "Autauga, AL",
"value": 5.6
},
{
"name": "Baldwin, AL",
"value": 5.3
},...
]
How can I retrieve the index of an array object if I just have the name "Autauga, AL"?
I am aware of the brute force loops. is there a better way?

In ECMAScript 5.1+, you can use the Array#filter method to get the actual object:
data.filter(function(item){return item.name == 'Autauga, AL'})[0]
That doesn't get you the index, though. You could do this:
data.map(function(item,index){
return [item, index]
}).filter(function(a){
return a[0].name == 'Autauga, AL'
})[0][1]
Those methods still wind up using loops under the covers, but I guess they look cooler..
For efficient access, you could build an index for the target field:
var dataIndexByName = {}, i, len;
for (i=0, len=data.length; i<len; ++i) {
dataIndexByName[data[i].name] = i
}
After which you can just look for dataIndexByName['Autauga, AL']. That also has the advantage of working in older implementations. It gets a bit more complicated if a given name might show up more than once in the original array, though.

You could do something like this:
for (var i = 0, len = data.length; i++) {
if (data[i].name.indexOf("Autauga, AL") > -1) {
return i;
}
}

You could write a small function to do the job based on Array.prototype.some:
function getIndex(arr, prop, value) {
var idx;
arr.some(function(v, i) {
if (v[prop] == value) {
idx = i;
return true;
}
});
return idx;
}
data = [{"name": "Autauga, AL","value": 5.6},
{"name": "Baldwin, AL","value": 5.3}];
console.log(getIndex(data, 'name', 'Baldwin, AL')); // 1
some is efficient because it stops when the callback first returns true. You may wisht to adjust the condition to suit.

Related

Create and store different arrays in each object

I'm new programming in JS and I'm designing an application to search for sites by county (it would be something like state) and municipality (Counties).
From the data I obtain through an API I get the following results.
data from API
As you can see there are some counties that are repeated and what I am interested in is to assign the county in an object and within that object create an array with its municipalities.
At the moment I have removed the repeated counties, but I cannot put each object with its municipalities.
API to array
My code is the following basically what I do here is to remove the repeated data from the counties.
(variable data is the values from API picture 1)
for(let i=0; i< data.length; i++)
{
let found = false;
for (var j=0; j<array.length; j++) {
if (data[i].nom_comarca == array[j].comarca) {
municipis.push(data[i].municipi)
found = true;
break;
}
}
if(!found) // If not find we add into Array
{
array.push({
comarca : data[i].nom_comarca,
municipis: municipis
})
//municipis = [];
}
}
Thanks for all really!!
Using a dictionary to keep track of duplicate nom_comarca. Transform the municipi property into an array if the element doesn't yet exist, otherwise push the municipi value to the existing element's array.
const data = [
{"nom_comarca": "1", "municipi": "1"},
{"nom_comarca": "1", "municipi": "2"},
{"nom_comarca": "2", "municipi": "3"},
];
const result = Object.values(data.reduce((acc, el) => {
if (!acc[el.nom_comarca]) {
acc[el.nom_comarca] = {...el, municipi: [el.municipi]};
} else {
acc[el.nom_comarca].municipi.push(el.municipi);
}
return acc;
}, {}));
console.log(result);

How can get a count with nested objects with a certain property?

Okay so I'm using angular to get a json saved to my computer to recreate a github gradebook.
I can get the data with my $http request but for the love of me all I want is to get a count of the number of issues with the label "Not Yet".
Here is the javascript:
$http.get('/api/github/repos/issues/all_issues/00All.json')
.then(function(response) {
console.log(response.data[0]);
var counter = 0;
for(var index = 0; index < response.data.length; index++) {
if(response.data[index].labels[0].name == "Not Yet") {
counter++;
};
};
console.log(counter);
});
That's the latest try, I also tried using lodash to get it earlier:
$http.get('/api/github/repos/issues/all_issues/00All.json')
.then(function(response) {
console.log(response);
mile.notYet.width = _.forEach(response.data, function(n){
var counter = 0;
if(_.result(_.find(n.labels[0], 'name')) == "Not Yet") {
counter++;
}
console.log(counter);
counter = ((counter/10) * 100) + '%';
});
});
This is a bit of the json data:
[
{
"url": "https://api.github.com/repos/TheIronYard--Orlando/2015--SUMMER--FEE/issues/11",
"labels_url": "https://api.github.com/repos/TheIronYard--Orlando/2015--SUMMER--FEE/issues/11/labels{/name}",
"comments_url": "https://api.github.com/repos/TheIronYard--Orlando/2015--SUMMER--FEE/issues/11/comments",
"events_url": "https://api.github.com/repos/TheIronYard--Orlando/2015--SUMMER--FEE/issues/11/events",
"html_url": "https://github.com/TheIronYard--Orlando/2015--SUMMER--FEE/issues/11",
"id": 73013825,
"number": 11,
"title": "00 -- Brace Yourself -- BEN GRIFFITH",
"user": {
"login": "Epicurean306",
"id": 11682684,
"avatar_url": "https://avatars.githubusercontent.com/u/11682684?v=3",
"gravatar_id": "",
"url": "https://api.github.com/users/Epicurean306",
"html_url": "https://github.com/Epicurean306",
"followers_url": "https://api.github.com/users/Epicurean306/followers",
"following_url": "https://api.github.com/users/Epicurean306/following{/other_user}",
"gists_url": "https://api.github.com/users/Epicurean306/gists{/gist_id}",
"starred_url": "https://api.github.com/users/Epicurean306/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/Epicurean306/subscriptions",
"organizations_url": "https://api.github.com/users/Epicurean306/orgs",
"repos_url": "https://api.github.com/users/Epicurean306/repos",
"events_url": "https://api.github.com/users/Epicurean306/events{/privacy}",
"received_events_url": "https://api.github.com/users/Epicurean306/received_events",
"type": "User",
"site_admin": false
},
"labels": [
{
"url": "https://api.github.com/repos/TheIronYard--Orlando/2015--SUMMER--FEE/labels/Not%20Yet",
"name": "Not Yet",
"color": "e11d21"
}
],
As you can see the labels property is an object, nested in an array, nested in an object, nested in an array, real lovely. Putting labels[0] results in an error for me each time and doesn't get me a count. Can anybody tell me where I'm messing up please? Thank you!
If you need a solution that includes lodash, which is much more performant than the native high order functions then you can try this solution below:
var size = _(response.data)
.pluck('labels')
.flatten()
.where({ name: 'Not Yet' })
.size();
UPDATE:
If you want it to be more reusable, you can save a reference for a cloned chained sequence and simply supply another array for that cloned sequence.
var data1 = [/*array from data1*/];
var data2 = [/*array from data2*/];
var notYetSequence = _(data1)
.pluck('labels')
.flatten()
.where({ name: 'Not Yet' });
notYetSequence.size(); // returns data 1 count
notYetSequence.plant(data2).size(); // returns data 2 count
You don't need lodash for the task
var cnt = response.data
.map(function(i) { return i.labels; })
// here we extract labels object only (and get an array of arrays of objects)
.map(function(i) { return i.filter(function(l) { return l.name == 'Not yet'; }).length; })
// then for every nested array we return a number of items with
// Not Yet names (and get an array of numbers)
.filter(function(c) { return c > 0; })
// then we filter issues that don't have one (and still get an array of numbers)
.length;
// and finally get length (which is a number)
As a comparison, a plain for loop looks like:
var data = response.data;
var count = 0;
var re = /not yet/i;
for (var a, i=0, iLen=data.length; i<iLen; i++) {
a = data[i].labels;
for (var j=0, jLen=a.length; j<jLen; j++) {
if (re.test(a[j].name)) ++count;
}
}
So really not a lot of code either way, the for loop will be compatible with every browser ever (though using xmlHTTPRequest means at least ed 3+) and fastest… untested of course. ;-)

Get all string values from a nested object

I have an object, with nested objects. How do I target a specific index of the object and loop through all the nested values of image. As you will note the length of the nested objects vary.
Target example: productArray[0].image = test1.png, test2.png, test3.png
var products = [
//item1
{
identifier: "item-0",
image: {
"img1": "test1.png",
"img2": "test2.png",
"img3": "test3.png"
}
},
//item2
{
identifier: "item-1",
image: {
"img1": "test1.png",
"img2": "test2.png"
}
},
//item3
{
identifier: "item-2",
image: {
"img1": "test1.png",
"img2": "test2.png",
"img3": "test3.png",
"img4": "test4.png",
"img5": "test5.png",
"img6": "test6.png",
"img7": "test7.png"
}
}
];
We can do this. What you need to do is a simple loop through the object at a specific index, or you can target them all. Note that the image object is not an array, so it will not have an accurate length property.
Target all indexes:
for(var i = 0; i < products.length; i++) {
console.log("Item: " + i);
var images = products[i].image;
for(var a in images)
console.log(images[a]);
}
Target specific:
for(var i in products[0].image)
console.log(products[0].image[i]);
I used a for loop here, but you can use a while loop if you would like.
example
Steps:
You need to iterate over your original array of products. products
Each element (product) will be in format { identifier: "", image : {"img1" : "img2", ..}} products[i]
You get the image property of current product - this is an object. products[i].image
Now you need to iterate over the properties of the image object. products[i].image[j]
Code:
for(var i = 0; i < products.length; i++)
{
for(var j in products[i].image)
{
// Here you have all the images for the current product.
// You can print them, group them or whatever you want to do with them
console.log(products[i].image[j]);
}
}
Also you can change the code (introduce variables) to be more readable.
var strs = (function( obj ) {
var ret = [];
for( im in obj ) {
ret.push( obj[im] );
//You could access each image URL here
//ad strs in the end will have all of them
//comma-separated after this code completes
// im is the key, obj[ im ] the value
}
return ret.join(',');
})( products[0].image );
console.log( strs );
WORKING JS FIDDLE DEMO
Here is another way of doing this, with newer functions in ECMAScript 5
var images = Object.keys(products[2].image).map(function(key){
return products[2].image[key]
})
console.log(images) // Returns: ["test1.png", "test2.png", "test3.png", "test4.png", "test5.png", "test6.png", "test7.png"]
How It Works:
Object#keys returns an array of key names. Array#map creates a new array using the keys from Object#keys. By looking up the key from the object you get the value, which will be the image name.
JS FIDDLE

How to dynamically grab a value using jquery for each?

So i've been stuck trying to figure this out. I'm pretty sure I'm lacking a key piece of information. I'm grabbing some values from a JSON response. One contains a list of names. Another contains a list of URLs that correspond to the list of Names.
For instance:
{"names":"john,casey,davey",
"nameUrls":[{
"johnURL":"http://url.com",
"caseyURL":"http://url.com",
"daveyURL":"http://url.com"]}
names = (data.names).split(',');
$.each(data.nameUrls, function(key, val) {
for (var i = 0; i < names.length; i++) {
$("#left").append(val[names[i] + "URL"]);
}
})
Now the first one comes through just fine. But the rest come in undefined. So what am I doing wrong? Thanks in advance for your help.
Edit: Adding more code.
After fixing some syntax errors, here's the code which I tested in console and it's working.
var data = {
"names": "john,casey,davey",
"nameUrls": {
"johnURL": "http://url.com",
"caseyURL": "http://url.com",
"daveyURL": "http://url.com"
}
};
names = (data.names).split(',');
$.each(data.nameUrls, function (key, val) {
for (var i = 0; i < names.length; i++) {
$("#left").append(val[names[i] + "URL"]);
}
});
In above lines, I just fixed the syntax errors, however I believe this might not let you achieve what you want. Try the below code and let me know.
var data = {
"names": "john,casey,davey",
"nameUrls": {
"johnURL": "http://url1.com",
"caseyURL": "http://url2.com",
"daveyURL": "http://url3.com"
}
};
names = (data.names).split(',');
$.each(data.nameUrls, function (key, val) {
$("#left").append(val);
});
It seems to me like you should restructure your data so that there is an easier association amongst it.
Would something like this work for you?
data = [
{"name": "john", "url": "http://url.com"},
{"name": "casey", "url": "http://url.com"},
{"name": "davey", "url": "http://url.com"}
];
$.each(data, function(index, person) {
$('#left').append(person.url);
});
var data = {
"names": "john,casey,davey",
"nameUrls": {
"johnURL": "http://url.com",
"caseyURL": "http://url.com",
"daveyURL": "http://url.com"
}
};
$.each(data.names.split(','), function (i, v) {
$("#left").append( v + " ==> " + data.nameUrls[v + 'URL'] );
});

javascript find in array

I have an array like this:
var movies = [
{ Name: "The Red Violin", ReleaseYear: "1998", Director: "François Girard" },
{ Name: "Eyes Wide Shut", ReleaseYear: "1999", Director: "Stanley Kubrick" },
{ Name: "The Inheritance", ReleaseYear: "1976", Director: "Mauro Bolognini" }
];
I want to find the location of the movie that's released in 1999.
Should return 1.
What's the easiest way?
Thanks.
You will have to iterate through each value and check.
for(var i = 0; i < movies.length; i++) {
if (movies[i].ReleaseYear === "1999") {
// i is the index
}
}
Since JavaScript has recently added support for most common collection operations and this is clearly a filter operation on a collection, instead you could also do:
var moviesReleasedIn1999 = movies.filter(function(movie) {
return movie.ReleaseYear == "1999";
});
assuming you're not interested in the indexes but the actual data objects. Most people aren't anyways :)
.filter is not supported in all browsers, but you can add it yourself to your code base:
https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/filter#Compatibility
Built in? Use loops.
You want to get fancy? Linq to Javascript: http://jslinq.codeplex.com/
Something like:
function findMovieIndices(movies, prop, value) {
var result = [];
for(var i = movies.length; i--; ) {
if(movies[i][prop] === value) {
result.push(i); // personally I would return the movie objects
}
}
return result;
}
Usage:
var indices = findMovieIndices(movies, "ReleaseYear", "1999");
Maybe this gives you some idea for a more generalized function (if you need it).
Since you've also tagged it with jQuery, you could use the 'map' function:
var movies = $.map(movies,function(item,index){
return item.ReleaseYear == 1999 ? index : null;
});
This will return an array of indexes for all movies with the year of 1999. If you wanted the movies themselves as an array:
var movies = $.map(movies,function(item){
return item.ReleaseYear == 1999 ? item : null;
});
If functional style programming is applicable:
_.indexOf(_.pluck(movies, "ReleaseYear"), "1999")
Because it's that simple. The functional toolkit that is underscore.js can be very powerful.
_.indexOf , ._pluck
You'll have to create your own searching function.
Array.prototype.findMovieByYear = function (findYear) {
for (var i = 0; i < this.length; i++) {
// this actually returns the element, maybe you just want
// to return the array index ( the i param )
if (this[i].Release == findYear) return this[i];
}
return null;
// or return -1 or whatever if you want to return the index
};
// now you can call:
movies.findMovieByYear('1998');
// and that should return
{ Name: "The Red Violin", ReleaseYear: "1998", Director: "François Girard" }
Of course, this way of doing it actually affects every array you create.. which is maybe not what you want.. you can create your own array object then ...

Categories