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 ...
Related
I want to write a function which checks if a keyword is contained in an object atrribute array. If the keyword is found in that array, it should return that object.
I tried the code below, but it doesn't work. I hope there is someone smart who can tell me what I have done wrong in this code :)
My goal is that function: Projects.detectProjectByKeyword("brumi") returns ImageObjects.DE.brumi
Or maybe there is an easier method to achieve the goal? I would very much appreciate any help, as I've been stuck here for more than a week :(
var ImageObjects = function() {
var DE = {
brumi : {
name:"Brummi-Werk",
keywords: ["brumi","auto", "LKWs", "lkws","lkw-werkstatt","die Brummis"]
},
medien : {
name: "medien",
keywords:["vier","nummer vier", "springer", "neue medien", "neue medien ag", "die neue medien ag"]
},
mautmaxe : {
name: "mau",
keywords:["fünf","nummer fünf", "mautmaxe", "maut", "currywust", "currywurst stand"]
}
};
return {
DE: DE
}
}();
function searchObj(obj, query) {
var data ='';
for (var property in obj) {
if (obj.hasOwnProperty(property)) {
if (typeof obj[property] === "object") {
data = searchObj(obj[property], query);
if(data !='') return data;
}
else {
if (obj["keywords"].indexOf(query) >= 0) {
return obj;
}
else {
return null;
}
}
}
}
return data;
}
var Projects = function() {
function detectProjectByKeyword(project) {
var foundObject = null;
for (var x in ImageObjects.DE){
if ((searchObj(ImageObjects.DE[x], project))!=null){
foundObject = searchObj(ImageObjects.DE[x], project)
}
}
return foundObject;
}
return {
detectProjectByKeyword: detectProjectByKeyword
}
}();
If the structure never changes, IE; ImageObjects.LANGUAGE.project.keywords, this will suffice:
function detectProjectByKeyword(keyword, obj, language) {
for(var a in obj[language]) {
if(obj[language].hasOwnProperty(a)) {
if(obj[language][a].keywords.indexOf(keyword) >= 0) return obj[language][a]
}
}
}
console.log(detectProjectByKeyword('brumi', ImageObjects, 'DE'));
console.log(detectProjectByKeyword('lkws', ImageObjects, 'DE'));
console.log(detectProjectByKeyword('mautmaxe', ImageObjects, 'DE'));
here's a sample: https://jsfiddle.net/jorgthuijls/o2a01p6h/
I've taken the liberty of changing your data structure slightly, but if I correctly understand what you're trying to do, then I'd expect something like the following to work:
var ImageObjects = {
DE: {
brumi : {
name: "Brummi-Werk",
keywords: [
"brumi","auto", "LKWs", "lkws","lkw-werkstatt","die Brummis"
]
},
medien : {
name: "medien",
keywords: [
"vier","nummer vier", "springer", "neue medien", "neue medien ag", "die neue medien ag",
/* added to demonstrate retrieving projects using a keyword shared across projects */, "brumi"
]
},
mautmaxe : {
name: "mau",
keywords: [
"fünf","nummer fünf", "mautmaxe", "maut", "currywust", "currywurst stand"
]
}
}
};
// Returns an array containing all projects with the keyword
// If only one project has a keyword, a one-element array will be returned
function findAllProjectsByKeyword(keyword) {
var results = [];
for (var country in ImageObjects) {
for (var project in ImageObjects[country]) {
var projectKeywords = ImageObjects[country][project].keywords;
if ( projectKeywords && projectKeywords.indexOf(keyword) != -1 ) {
results.push(ImageObjects[country][project]);
}
}
}
return results;
}
// Returns a single project with keyword
// If multiple projects have a keyword, only one will be returned
// The one that is returned may vary even for the same data, because the order
// of for-in loop enumeration may vary across implementations/runs
function findProjectByKeyword(keyword) {
for (var country in ImageObjects) {
for (var project in ImageObjects[country]) {
var projectKeywords = ImageObjects[country][project].keywords;
if ( projectKeywords && projectKeywords.indexOf(keyword) != -1 ) {
return ImageObjects[country][project];
}
}
}
}
// Example where a keyword is shared by two projects
var brumiProjects = findAllProjectsByKeyword('brumi');
console.log(brumiProjects.length); // <= 2
console.log(brumiProjects[0].name); // <= Brummi-Werk
console.log(brumiProjects[1].name); // <= medien
// Only one project is returned with findProjectByKeyword, even if multiple projects have that keyword
console.log(findProjectByKeyword('brumi').name); // <= Brummi-Werk (could be medien), depending on how the object is enumerated
// Example where only one project has a keyword
console.log(findAllProjectsByKeyword('vier')[0].name); // <= medien
console.log(findProjectByKeyword('vier').name); // <= medien
The ImageObjects structure has three levels, country (I assume), project, and project info (name and keywords). findAllProjectsByKeyword loops through the first two levels so that it searches all projects in all countries. For each project, it searches for the keyword (passed as an argument to findAllProjectsByKeyword) in the keywords array in the project object; if the keyword is found, then Array.indexOf returns the index--otherwise, it returns -1. If the keyword is found, then the found project object is pushed into the results array. findAllProjectsByKeyword will find multiple projects given a single keyword. findProjectByKeyword uses the same approach but returns only the first project found for a given keyword.
There are other subtleties you might want to consider; for instance, Array.indexOf is case-sensitive, so if you search for keyword 'Brumi', you won't get any results.
What about finding objects by more than a keyword and using modern ECMA-Script 2015 and above tooling and awesomeness?
See comments on the following code snippet to get insights to understand the whole solution:
var ImageObjects = {
DE: {
brumi: {
name: "Brummi-Werk",
keywords: [
"brumi", "auto", "LKWs", "lkws", "lkw-werkstatt", "die Brummis"
]
},
medien: {
name: "medien",
keywords: [
"vier", "nummer vier", "springer", "neue medien", "neue medien ag", "die neue medien ag", "mautmaxe"
]
},
mautmaxe: {
name: "mau",
keywords: [
"fünf", "nummer fünf", "mautmaxe", "maut", "currywust", "currywurst stand", "springer"
]
}
}
};
// #1 Second parameter is a rest parameter. Second and any other parameter
// will be captured as an array called "keywords"
//
// #2 Object.keys returns own given object's properties (you don't need to
// filter them out with x.hasOwnProperty("blah"))
//
// #3 For each property of a given language object, filter those
// that contain the whole given keywords. The "...keywords" will
// call Array.prototype.includes as many times as keywords you've
// provided, and the operation will be done like using && (AND) logical
// operator: all keywords should be present or it will be false.
//
// #4 Finally, Array.prototype.map gets the whole found property and returns
// the object held by that property!
var findByKeywords = (language, ...keywords) =>
Object.keys(ImageObjects[language])
.filter(property => ImageObjects[language][property].keywords.includes(...keywords))
.map(property => ImageObjects[language][property]);
var result = findByKeywords("DE", "mautmaxe", "springer");
console.log(result);
Further reading:
Spread syntax
Rest parameters
I have just started to pick up coding seriously. :)
I came across a problem that seems too complicated for me.
How to group the following products by promotions type?
var data = [
{
name:'product1',
price:'40',
promotion:[
{
name:'Buy 3 get 30% off',
code:'ewq123'
},
{
name:'Free Gift',
code:'abc140'
}
]
},
{
name:'product2',
price:'40',
promotion:[
{
name:'Buy 3 get 30% off',
code:'ewq123'
}
]
},
{
name:'product3',
price:'40',
promotion:[
{
name:'Buy 3 get 30% off',
code:'ewq123'
}
]
},
{
name:'product4',
price:'40'
},
{
name:'product5',
price:'40',
promotion:[
{name:'30% off', code:'fnj245'}
]
},
{
name:'product6',
price:'0',
promotion:[
{
name:'Free Gift',
code:'abc140'
}
]
}
];
I would like to get result in the following format
result =[
{
name : 'Buy 3 get 30% off',
code: 'ewq123',
products: [
... array of products
]
},
{
name : '30% off',
code: 'fnj245',
products: [
... array of products
]
},
{
...
}
];
I am able to get a list of products by promotion code, but how can I make it generic?
function productHasPromo(product, promotion){
if(!product.hasOwnProperty('promotion')) return false;
var productPromo = product.promotion;
for(var i=0; i<productPromo.length; i++){
if(productPromo[i].code === promotion){
return true;
}
}
return false;
}
function groupProductByPromo(products, promotion){
var arr = [];
for(var i=0; i<products.length; i++){
if(productHasPromo(products[i], promotion)){
arr.push(products[i]);
}
}
return arr;
}
Explanation
You could write a function that loops through your array and search for the unique values within a specified property. That is easily done when working with simple data types, but can be done with more complex structures as arrays of objects (like in your example), using a helper grouping function.
Since you also need the output to be in a specific format after the grouping, we will have to work on a transformer also. This transformer will receive the original data and the unique values extracted by the grouping function, and will generate the desired output.
The following functions were used in the example:
Array.prototype.groupBy = function (property, grouping, transformer) {
var values = [];
this.forEach(function (item) {
grouping.call(this, item, property).forEach(function (item) {
if (!values.contains(property, item[property])) {
values.push(item);
}
});
});
return transformer.call(this, values);
};
Array.prototype.contains = function (key, value) {
return this.find(function (elm) {
return elm[key] === value;
});
};
function transformerFunction(values) {
this.forEach(function (item) {
if (!item.promotion) return;
item.promotion.forEach(function (promotion) {
values.forEach(function (option) {
if (option.code === promotion.code) {
if (option.products) {
option.products.push(item);
} else {
option.products = [item];
}
}
});
});
});
return values;
}
function groupingFunction(item, property) {
if (!item.promotion) return [];
var values = [];
item.promotion.forEach(function (promotion) {
if (!values.contains(property, promotion[property])) {
values.push(promotion);
}
});
return values;
}
Usage as follows:
var items = data.groupBy('code', groupFunction, transformFunction);
Example
Check the example i've prepared at jsfiddle
Welcome to the coding world. A lot of people start off with a problem by trying to write some code, then they wonder why it doesn't work and scratch their heads, don't know the basics of debugging it, and then post here to SO. They're missing the crucial first step in programming which is to figure out how you are going to do it. This is also called designing the algorithm. Algorithms are often described using something called pseudo-code. It has the advantage that it can be looked at and understood and established to do the right thing, without getting bogged down in all the mundane details of a programming language.
There are some algorithms that are figured out by some very smart people--like the Boyer-Moore algorithm for string matching--and then there are other algorithms that programmers devise every day as part of their job.
The problem with SO is that all too often someone posts a question which essentially about an algorithm, and then all the keyboard-happy code jockeys pounce it and come up with a code fragment, which in many cases is so contorted and obtuse that one cannot even see what the underlying algorithm is.
What is the algorithm you propose for solving your problem? You could post that, and people would probably give you reasonable comments, and/or if you also give an actual implementation that doesn't work for some reason, help you understand where you've gone wrong.
At the risk of robbing you the pleasure of devising your own algorithm for solving this problem, here's an example:
Create an empty array for the results.
Loop through the products in the input.
For each product, loop through its promotions.
Find the promotion in the array of results.
If there is no such promotion in the array of results, create a new one, with an empty list of products.
Add the product to the array of products in the promotion entry in the array.
In pseudo-code:
results = new Array // 1
for each product in products (data) // 2
for each promotion in promotions field of product // 3
if results does not contain promotion by that name // 4
add promotion to results, with empty products field // 5
add product to products field of results.promotion // 6
If we believe this is correct, we can now try writing this in JavaScript.
var result = []; // 1
for (var i = 0; i < data.length; i++) { // 2
var product = data[i];
var promotions = product.promotion;
for (var j = 0; j < promotions.length; j++) { // 3
var promotion = promotions[i];
var name = promotion.name;
var result_promotion = find_promotion_by_name(name);
if (!result_promotion) { // 4
result_promotion = { name: name, products: [], code: promotion.code };
result.push(result_promotion); // 5
}
result_promotion.products.push(name); // 6
}
}
This code is OK, and it should get the job done (untested). However, it is still a bit unreadable. It does not follow the pseudo-code very closely. It somehow still hides the algorithm. It is hard to be sure that it is completely correct. So, we want to rewrite it. Functions like Array#foreach make it easier to do this. the top level can simply be:
var result = [];
data.forEach(processProduct);
In other words, call the processProduct function for each element of data (the list of products). It will be very hard for this code to be wrong, as long as `processProduct is implemented incorrectly.
function processProduct(product) {
product.promotion.forEach(processPromotion);
}
Again, this logic is provably correct, assuming processPromotion is implemented correctly.
function processPromotion(promotion) {
var result_promotion = getPromotionInResults(promotion);
result_promotion.products.push(name);
}
This could hardly be clearer. We obtain the entry for this promotion in the results array, then add the product to its list of products.
Now we need to simply implement getPromotionInResults. This will include the logic to create the promotion element in the results array if it doesn't exist.
function getPromotionInResults(promotion) {
var promotionInResults = findPromotionInResultsByName(promotion.name);
if (!promotionInResults) {
promotionInResults = {name: promotion.name, code: promotion.code, products: []};
result.push(promotionInResults);
}
return promotionInResults;
}
This also seems demonstrably correct. But we still have to implement findPromotionInResultsByName. For that, we can use Array#find, or some equivalent library routine or polyfill:
function findPromotionInResultsByName(name) {
return result.find(function(promotion) {
return promotion.name === name;
});
}
The entire solution is thus
function transform(data) {
// Given a product, update the result accordingly.
function processProduct(product) {
product.promotion.forEach(processPromotion);
}
// Given a promotion, update its list of products in results.
function processPromotion(promotion) {
var result_promotion = getPromotionInResults(promotion);
result_promotion.products.push(name);
}
// Find or create the promotion entries in results.
function getPromotionInResults(promotion) {
var promotionInResults = findPromotionInResultsByName(promotion.name);
if (!promotionInResults) {
promotionInResults = {name: promotion.name, code: promotion.code, products: []};
result.push(promotionInResults);
}
return promotionInResults;
}
// Find an existing entry in results, by its name.
function findPromotionInResultsByName(name) {
return result.find(function(promotion) {
return promotion.name === name;
});
}
var result = [];
data.forEach(processProduct);
return result;
}
Ok, after a few hours of works, with lots of help online and offline, I finally made it works. Thanks for the people who has helped.
Please do comment if you have a more elegant solution, always love to learn.
For people who ran into similar problem:
Here is my solution
function groupProductsByPromo(data){
var result = [];
// filter only product with promotion
var productsWithPromo = data.filter(function(product){
return product.hasOwnProperty('promotions');
});
// create promotions map
var mappedProducts = productsWithPromo.map(function(product) {
var mapping = {};
product.promotions.forEach(function(promotion) {
mapping[promotion.code] = {
promotion: promotion
};
});
return mapping;
});
// reduce duplicates in promotion map
mappedProducts = mappedProducts.reduce(function(flattenObject, mappedProducts) {
for (var promoCode in mappedProducts) {
if (flattenObject.hasOwnProperty(promoCode)) {
continue;
}
flattenObject[promoCode] = {
code: promoCode,
name: mappedProducts[promoCode].promotion.name
};
}
return flattenObject;
}, {});
// add products to promo item
for(var promoCode in mappedProducts){
mappedProducts[promoCode].products = productsWithPromo.filter(function(product){
return product.promotions.some(function(promo){
return promo.code === promoCode;
});
});
result.push(mappedProducts[promoCode]);
}
return result;
}
Check out lodash - a nifty library for doing all sorts of transforms.
lodash.groupBy is what you're looking for.
I am using Ionic with AngularJS and I am using a localForage database and AJAX via $http. My app has a news stream that contains data like this:
{
"feed":[
{
"id":"3",
"title":"Ein Hund",
"comments:"1"
},
{
"id":"2",
"title":"Eine Katze",
"comments":"2"
}
],
"ts":"20150907171943"
}
ts stands for Timestamp. My app saves the feed locally via localForage.
When the app starts it first loads the locally saved items:
$localForage.getItem("feed").then(function(val) { vm.feed = val; })
Then, it loads the new or updated items (ts < current timestamp) and merges both the old and new data:
angular.extend(vm.feed, response.data.feed);
Updated items look like this:
{
"feed":[
{
"id":"2",
"title":"Eine Katze",
"comments":"4"
}
],
"ts":"20150907171944"
}
That is, the comments count on feed item 2 has changed from 2 to 4. When I merge the old and new data, vm.feed has two items with id = 2.
Does angularjs has a built-in "merge by id" function, i. e. copy from source to destination (if it is a new element), or otherwise replace the old element? In case angularjs does not have such a function, what's the best way to implement this?
Thanks in advance!
angular.merge(vm.feed, response.data.feed);
// EDIT
Probably, it will not merge correctly, so you have to update all properties manually. Update ts property and then find your object with id and replace it.
There is no builtin, I usually write my own merge function:
(function(){
function itemsToArray(items) {
var result = [];
if (items) {
// items can be a Map, so don't use angular.forEach here
items.forEach(function(item) {
result.push(item);
});
}
return result;
}
function idOf(obj) {
return obj.id;
}
function defaultMerge(newItem, oldItem) {
return angular.merge(oldItem, newItem);
}
function mergeById(oldItems, newItems, idSelector, mergeItem) {
if (mergeItem === undefined) mergeItem = defaultMerge;
if (idSelector === undefined) idSelector = idOf;
// Map retains insertion order
var mapping = new Map();
angular.forEach(oldItems, function(oldItem) {
var key = idSelector(oldItem);
mapping.set(key, oldItem);
});
angular.forEach(newItems, function(newItem) {
var key = idSelector(newItem);
if (mapping.has(key)) {
var oldItem = mapping.get(key);
mapping.set(key, mergeItem(newItem, oldItem));
} else {
// new items are simply added, will be at
// the end of the result list, in order
mapping.set(key, newItem);
}
});
return itemsToArray(mapping);
}
var olds = [
{ id: 1, name: 'old1' },
{ id: 2, name: 'old2' }
];
var news = [
{ id: 3, name: 'new3' },
{ id: 2, name: 'new2' }
];
var merged = mergeById(olds, news);
console.log(merged);
/* Prints
[
{ id: 1, name: 'old1' },
{ id: 2, name: 'new2' },
{ id: 3, name: 'new3' }
];
*/
})();
This builds a Map from the old items by id, merges in the new items, and converts the map back to list. Fortunately the Map object will iterate on the entries in insertion order, according to the specification. You can provide your idSelector and mergeItem functions.
Thanks hege_hegedus. Based on your code, I've written my own and tried to use less loops to speed things up a bit:
function updateCollection(localCollection, fetchedCollection) {
angular.forEach(fetchedCollection, function(item) {
var append = true;
for (var i = 0; i < localCollection.length; i++) {
if (localCollection[i].id == item.id) {
// Replace item
localCollection[i] = item;
append = false;
break;
} else if (localCollection[i].id > item.id) {
// Add new element at the right position, if IDs are descending check for "< item.id" instead
localCollection.splice(i, 0, item);
append = false;
break;
}
}
if (append) {
// Add new element with a higher ID at the end
localCollection.push(item);
// When IDs are descending use .unshift(item) instead
}
});
}
There is still room for improvements, i. e. the iteration through all the objects should use binary search since all items are sorted by id.
I have the following JSON -
{
"node1":[
{
"one":"foo",
"two":"foo",
"three":"foo",
"four":"foo"
},
{
"one":"bar",
"two":"bar",
"three":"bar",
"four":"bar"
},
{
"one":"foo",
"two":"foo",
"three":"foo",
"four":"foo"
}
],
"node2":[
{
"link":"baz",
"link2":"baz"
},
{
"link":"baz",
"link2":"baz"
},
{
"link":"qux",
"link2":"qux"
},
]
};
I have the following javascript that will remove duplicates from the node1 section -
function groupBy(items, propertyName) {
var result = [];
$.each(items, function (index, item) {
if ($.inArray(item[propertyName], result) == -1) {
result.push(item[propertyName]);
}
});
return result;
}
groupBy(catalog.node1, 'one');
However this does not account for dupicates in node2.
The resulting JSON I require is to look like -
{
"node1":[
{
"one":"foo",
"two":"foo",
"three":"foo",
"four":"foo"
},
{
"one":"bar",
"two":"bar",
"three":"bar",
"four":"bar"
}
],
"node2":[
{
"link":"baz",
"link2":"baz"
},
{
"link":"qux",
"link2":"qux"
},
]
};
However I cannot get this to work and groupBy only returns a string with the duplicates removed not a restructured JSON?
You should probably look for some good implementation of a JavaScript set and use that to represent your node objects. The set data structure would ensure that you only keep unique items.
On the other hand, you may try to write your own dedup algorithm. This is one example
function dedup(data, equals){
if(data.length > 1){
return data.reduce(function(set, item){
var alreadyExist = set.some(function(unique){
return equals(unique, item);
});
if(!alreadyExist){
set.push(item)
}
return set;
},[]);
}
return [].concat(data);
}
Unfortunately, the performance of this algorithm is not too good, I think somewhat like O(n^2/2) since I check the set of unique items every time to verify if a given item exists. This won't be a big deal if your structure is really that small. But at any rate, this is where a hash-based or a tree-based algorithm would probably be better.
You can also see that I have abstracted away the definition of what is "equal". So you can provide that in a secondary function. Most likely the use of JSON.stringify is a bad idea because it takes time to serialize an object. If you can write your own customized algorithm to compare key by key that'd be probably better.
So, a naive (not recommended) implementation of equals could be somewhat like the proposed in the other answer:
var equals = function(left, right){
return JSON.stringify(left) === JSON.stringify(right);
};
And then you could simply do:
var res = Object.keys(source).reduce(function(res, key){
res[key] = dedup(source[key], equals);
return res;
},{});
Here is my version:
var obj = {} // JSON object provided in the post.
var result = Object.keys(obj);
var test = result.map(function(o){
obj[o] = obj[o].reduce(function(a,c){
if (!a.some(function(item){
return JSON.stringify(item) === JSON.stringify(c); })){
a.push(c);
}
return a;
},[]); return obj[o]; });
console.log(obj);//outputs the expected result
Using Array.prototype.reduce along with Array.prototype.some I searched for all the items being added into the new array generated into Array.prototype.reduce in the var named a by doing:
a.some(function(item){ return JSON.stringify(item) === JSON.stringify(c); })
Array.prototype.some will loop trough this new array and compare the existing items against the new item c using JSON.stringify.
Try this:
var duplicatedDataArray = [];
var DuplicatedArray = [];
//Avoiding Duplicate in Array Datas
var givenData = {givenDataForDuplication : givenArray};
$.each(givenData.givenDataForDuplication, function (index, value) {
if ($.inArray(value.ItemName, duplicatedDataArray) == -1) {
duplicatedDataArray.push(value.ItemName);
DuplicatedArray.push(value);
}
});
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.