I am having an array of object. And I am looping every object and performing some operation and again in the end splice that element from that array.
But I am not been able to achieve the desired result.
Here is what I have tried:
This is a sample array:
var arraylist=[{"username":"fzxd","contry":"vxcvxc"},
{"username":"fzxdfsdf","contry":"vxcvxc"},
{"username":"fsd","contry":"fsdf"},
{"username":"fsdf","contry":"werr"}];
var l = arraylist.length;
for(var i = 0; i < l; i++)
{
// For looping the item and doing some operation..
console.log(arraylist[i].username + " " + arraylist.length);
arraylist.splice(i,1); //In the end splicing it from the actual arraylist
}
When I run this only get fzxd 4 and fsd 3 printed on my log and not all elements.
Where I am doing wrong? Please guide me. Thanks!
If you splice out the first element, the element that was at the second position is now at the first position, the element at the second position is the third one. Therefore you will skip the second one. Instead of accessing arraylist[i] take arraylist[0] as well as arraylist.splice(0, 1). Or just:
let users = [{ /*...*/ }, /*...*/ ];
for(const user of users) {
// do stuff with user
}
users = []; // clear array.
on last operation arraylist.length less then index;
.splice it's side effect operation and after every calls as a result your index was moved and your array was changed.
var arraylist = [{ "username": "fzxd", "contry": "vxcvxc" }, { "username": "fzxdfsdf", "contry": "vxcvxc" }, { "username": "fsd", "contry": "fsdf" }, { "username": "fsdf", "contry": "werr" }]
var l = arraylist.length;
for (var i = 0; i < l; i++) {
//For looping the item and doing some operation..
console.log(arraylist.length, i) // on last operation arraylist.length less then index
//console.log(arraylist[i].username + " " + arraylist.length);
arraylist.splice(i, 1); //In the end splicing it from the actual arraylist
}
You can do it like this:
var arraylist = [{ "username": "fzxd", "contry": "vxcvxc" }, { "username": "fzxdfsdf", "contry": "vxcvxc" }, { "username": "fsd", "contry": "fsdf" }, { "username": "fsdf", "contry": "werr" }]
for(var i=arraylist.length-1; i>=0; i--)
{
console.log(arraylist[i].username);
arraylist.splice(i,1);
}
I hope this meets your requirement. Thanks!
Related
I'm trying to write an order form for a food delivery website (to learn more about objects in Javascript), so that each item, when selected, populates an array. It should also recognise the quantity requested, if an item is clicked twice, and not create a duplicate. This is my code, which works, but seems overlong. In particular, my final for loop, for increasing quantity, seems as if it should be superfluous. Is there a smarter way doing this?
The JSON data I'm drawing from looks like this:
"dishes": [
{
"id": "1",
"name": "Jumbo Chicken Wings",
"description": "Honey, Ginger, Chilli, Soy",
"price": "4.50"
},
{
"id": "2",
"name": "Spiced Whitebait",
"description": "Lemon Mayonaise",
"price": "5"
}
And this is my (probably overlong) code:
// ORDER FORM
// begin with empty array
var orderform = [];
function chooseDish() {
// when clicking on item...
$("#menu li").click(function(){
//create new object from item listed properties
var item = {
id: $(this).attr('id'),
dish: $(this).find("span.dish-name").text(),
price: $(this).find("span.dish-price").text()
};
// either add first item to array...
if (!orderform.length) {
item.quantity = 1;
orderform.push(item);
}
// or see if an object is already in the array.
else {
var hasDishBeenSelected = false;
for (var i = 0; i < orderform.length; i++) {
if (orderform[i].id === item.id) {
hasDishBeenSelected = true;
}
}
// if the item hasn't already been selected add the item...
if (!hasDishBeenSelected) {
item.quantity = 1;
orderform.push(item);
}
// otherwise increase that item's quantity by 1
else {
for (var j = 0; j < orderform.length; j++) {
if (orderform[j].id === item.id) {
orderform[j].quantity += 1;
}
}
}
}
console.table(orderform);
});
}
Thanks for any tips!
I am trying to figure out an efficient way to remove objects that are duplicates from an array and looking for the most efficient answer. I looked around the internet everything seems to be using primitive data... or not scalable for large arrays. This is my current implementation which is can be improved and want to try to avoid labels.
Test.prototype.unique = function (arr, artist, title, cb) {
console.log(arr.length);
var n, y, x, i, r;
r = [];
o: for (i = 0, n = arr.length; i < n; i++) {
for (x = 0, y = r.length; x < y; x++) {
if (r[x].artist == arr[i].artist && r[x].title == arr[i].title) {
continue o;
}
}
r.push(arr[i]);
}
cb(r);
};
and the array looks something like this:
[{title: sky, artist: jon}, {title: rain, artist: Paul}, ....]
Order does not matter, but if sorting makes it more efficient then I am up for the challenge...
and for people who do not know o is a label and it is just saying jump back to the loop instead of pushing to the new array.
Pure javascript please no libs.
ANSWERS SO FAR:
The Performance Test for the answers below:
http://jsperf.com/remove-duplicates-for-loops
I see, the problem there is that the complexity is squared. There is one trick to do it, it's simply by using "Associative arrays".
You can get the array, loop over it, and add the value of the array as a key to the associative array. Since it doesn't allow duplicated keys, you will automatically get rid of the duplicates.
Since you are looking for title and artist when comparing, you can actually try to use something like:
var arrResult = {};
for (i = 0, n = arr.length; i < n; i++) {
var item = arr[i];
arrResult[ item.title + " - " + item.artist ] = item;
}
Then you just loop the arrResult again, and recreate the array.
var i = 0;
var nonDuplicatedArray = [];
for(var item in arrResult) {
nonDuplicatedArray[i++] = arrResult[item];
}
Updated to include Paul's comment. Thanks!
Here is a solution that works for me.
Helper functions:
// sorts an array of objects according to one field
// call like this: sortObjArray(myArray, "name" );
// it will modify the input array
sortObjArray = function(arr, field) {
arr.sort(
function compare(a,b) {
if (a[field] < b[field])
return -1;
if (a[field] > b[field])
return 1;
return 0;
}
);
}
// call like this: uniqueDishes = removeDuplicatesFromObjArray(dishes, "dishName");
// it will NOT modify the input array
// input array MUST be sorted by the same field (asc or desc doesn't matter)
removeDuplicatesFromObjArray = function(arr, field) {
var u = [];
arr.reduce(function (a, b) {
if (a[field] !== b[field]) u.push(b);
return b;
}, []);
return u;
}
and then simply call:
sortObjArray(dishes, "name");
dishes = removeDuplicatesFromObjArray(dishes, "name");
Basic sort-then-unique implementation, fiddle HERE:
function unique(arr) {
var comparer = function compareObject(a, b) {
if (a.title == b.title) {
if (a.artist < b.artist) {
return -1;
} else if (a.artist > b.artist) {
return 1;
} else {
return 0;
}
} else {
if (a.title < b.title) {
return -1;
} else {
return 1;
}
}
}
arr.sort(comparer);
console.log("Sorted: " + JSON.stringify(arr));
for (var i = 0; i < arr.length - 1; ++i) {
if (comparer(arr[i], arr[i+1]) === 0) {
arr.splice(i, 1);
console.log("Splicing: " + JSON.stringify(arr));
}
}
return arr;
}
It may or may not be the most efficient, and should be entirely scalable. I've added some console.logs so you can see it as it works.
EDIT
In the interest of saving on the space the function used, I did that for loop at the end, but it seems likely that didn't properly find only unique results (depsite it passing my simple jsfiddle test). Please try replacing my for loop with the following:
var checker;
var uniqueResults = [];
for (var i = 0; i < arr.length; ++i) {
if (!checker || comparer(checker, arr[i]) != 0) {
checker = arr[i];
uniqueResults.push(checker);
}
}
return uniqueResults;
I use this function. its not doing any sorting, but produces result. Cant say about performance as never measure it.
var unique = function(a){
var seen = [], result = [];
for(var len = a.length, i = len-1; i >= 0; i--){
if(!seen[a[i]]){
seen[a[i]] = true;
result.push(a[i]);
}
}
return result;
}
var ar = [1,2,3,1,1,1,1,1,"", "","","", "a", "b"];
console.log(unique(ar));// this will produce [1,2,3,"", "a", "b"] all unique elements.
Below is Henrique Feijo's answer with ample explanation and an example that you can cut and paste:
Goal: Convert an array of objects that contains duplicate objects (like this one)...
[
{
"id": 10620,
"name": "Things to Print"
},
{
"id": 10620,
"name": "Things to Print"
},
{
"id": 4334,
"name": "Interesting"
}
]
... Into an array of objects without duplicate objects (like this one):
[
{
"id": 10620,
"name": "Things to Print"
},
{
"id": 4334,
"name": "Interesting"
}
]
Explanation provided in the comments:
var allContent = [{
"id": 10620,
"name": "Things to Print"
}, {
"id": 10620,
"name": "Things to Print"
}, {
"id": 4334,
"name": "Interesting"
}]
//Put Objects Into As Associative Array. Each key consists of a composite value generated by each set of values from the objects in allContent.
var noDupeObj = {} //Create an associative array. It will not accept duplicate keys.
for (i = 0, n = allContent.length; i < n; i++) {
var item = allContent[i]; //Store each object as a variable. This helps with clarity in the next line.
noDupeObj[item.id + "|" + item.name] = item; //This is the critical step.
//Here, you create an object within the associative array that has a key composed of the two values from the original object.
// Use a delimiter to not have foo+bar handled like fo+obar
//Since the associative array will not allow duplicate keys, and the keys are determined by the content, then all duplicate content are removed.
//The value assigned to each key is the original object which is along for the ride and used to reconstruct the list in the next step.
}
//Recontructs the list with only the unique objects left in the doDupeObj associative array
var i = 0;
var nonDuplicatedArray = [];
for (var item in noDupeObj) {
nonDuplicatedArray[i++] = noDupeObj[item]; //Populate the array with the values from the noDupeObj.
}
console.log(nonDuplicatedArray)
For those who love ES6 and short stuff, here it's one solution:
const arr = [
{ title: "sky", artist: "Jon" },
{ title: "rain", artist: "Paul" },
{ title: "sky", artist: "Jon" }
];
Array.from(arr.reduce((a, o) => a.set(o.title, o), new Map()).values());
const arr = [
{ title: "sky", artist: "Jon" },
{ title: "rain", artist: "Paul" },
{ title: "sky", artist: "Jon" },
{ title: "rain", artist: "Jon" },
{ title: "cry", artist: "Jon" }
];
const unique = Array.from(arr.reduce((a, o) => a.set(o.title, o), new Map()).values());
console.log(`New array length: ${unique.length}`)
console.log(unique)
The above example only works for a unique title or id. Basically, it creates a new map for songs with duplicate titles.
Below code compares object with JSON as String format and removes duplicates and works fine with simple arrays.
Array.prototype.unique=function(a){
return function(){
return this.filter(a)
}
}(
function(a,b,c){
var tmp=[];
c.forEach(function(el){
tmp.push(JSON.stringify(el))
});
return tmp.indexOf(JSON.stringify(a),b+1)<0
})
If you are using underscore js, it is easy to remove duplicate object.
http://underscorejs.org/#uniq
function remove_duplicates(objectsArray) {
var arr = [], collection = [];
$.each(objectsArray, function (index, value) {
if ($.inArray(value.id, arr) == -1) {
arr.push(value.id);
collection.push(value);
}
});
return collection;
}
I have two arrays (data and data_not_included).Each elemet of those arrays has attridutes id and name. I fill them this way:
data[i] = {
name :products.models[i].get('name'),
id : products.models[i].get('id')
};
Now I want do display the elements in data which are not in data_not_included array. For example I have
data=[{name: Sugar}{id: 1},{name: Butter}{id: 2},{name: Cola}{id: 3}]
// and
data_nat_included = [{name: Sugar}{id: 1},{name: Butter}{id: 2}].
It should display {name: Cola}{id: 3} only.
Here is what I have already done:
for(var j=0;j<data_not_icluded.length;j++)
{
for(var i=0;i<data.length;i++)
{
if(data[i].id != data_not_icluded[j].id ){
//but this doesnt work for me it displayes a lot of element many times
}
}
}
Both answers are asymptotically bad. This means they run in suboptimal time. In other words, they are naive approaches to solving the problem. This problem is more widely known in the domain of databases, where join operation is a commonplace. It is also known that the complexity of a join is O(log n * n + log m * m) where n is the number of elements in first table and m is the number of elements in the second table. This is fewer operations then would be required by naive solution offered in other examples O(n^2).
However, if more is known about your data, as, for example, I would expect that the values are unique and easily serializable to string, you could even reduce the complexity to O(n + m) by simply creating hashes of the objects you want to compare. Here's how to do it:
Where n is the number of elements in the first array and m is the number of elements in the second array.
var data = [{ name: "Sugar" },
{ id: 1 },
{ name: "Butter" },
{ id: 2 },
{ name: "Cola" },
{ id: 3 }];
var dataNatIncluded = [{ name: "Sugar" },
{ id: 1 },
{ name: "Butter" },
{ id: 2 }];
function join(a, b) {
var hashA = {}, hashB = {}, p, result = [];
function setter(hash) {
return function (element) { hash[JSON.stringify(element)] = element; };
}
a.forEach(setter(hashA));
b.forEach(setter(hashB));
for (p in hashB) delete hashA[p];
for (p in hashA) result.push(hashA[p]);
return result;
}
// [{ name: "Cola" }, { id: 3 }]
A simple way to do that:
var vals = [];
for(var i=0;i<data.length;i++)
{
var found = false;
for(var j=0;j<data_nat.length;j++)
{
if(data[i].id == data_nat[j].id ){
found = true;
break;
}
}
if (!found) vals.push(data[i]);
}
JSFiddle
for(var j=0;j<data_not_icluded.length;j++)
for(var i=0;i<data.length;i++)
if(data[i].id != data_not_icluded[j].id )
Think of what this does: For any not included object, show all objects that have not the same id as the current not included one. This will show many items multiple times, and it will show objects that are in "not included" but at another position.
Instead, loop over data, check each that it is not included in data_not_included, and display it otherwise:
dataloop: for (var i=0; i<data.length; i++) {
for (var j=0; j<data_not_included.length; j++)
if (data[i].id == data_not_icluded[j].id)
continue dataloop;
display(data[i]);
}
Or, using some iteration methods of Arrays:
data.filter(function(d) {
return data_not_included.every(function(n) {
return d.id != n.id;
});
}).each(display);
var d=getEntity( {"Division":
{
"oddTerms":
[
{
"entity": "Sunshine",
"Sunshine": [
{
"count": 2,
"entity": "Dodge"
},
{
"count": 1,
"entity": "Dodge Avenger"
},
]
}
]
}});
I want to traverse through the json string and the the entity names Dodge and Dodge Avenger. Ive used the following method
for (var k in h.Division.oddTerms)
{
s=h.Division.oddTerms[k].entity;
h.Division.oddTerms[k].+s+.entity;
}
But I do think this its not the correct methd to concatenate as it is not wrking.. anyone knows the correct format?
oddTerms is an Array, not an Object. For arrays in JavaScript you need to use a for loop with a counter instead of iterating through the elements:
var concatedString = '';
for (var k=0; k<h.Division.oddTerms.length;k++)
{
// Get the name of the entity we want to collect the entity terms of
var entityName =h.Division.oddTerms[k].entity;
// iterate through all the instances of each entity
for(var j=0; j<h.Division.oddTerms[k][entityName].length;j++){
concatedString += h.Division.oddTerms[k][entityName][j].entity;
}
}
var entityName = "",
arrTerms = [],
outputTemplate = '{"%entityName":[%terms]}',
h = {
"Division":
{
"oddTerms":
[
{
"entity": "Sunshine",
"Sunshine": [
{
"count": 2,
"entity": "Dodge"
},
{
"count": 1,
"entity": "Dodge Avenger"
},
]
}
]
}
};
for (var i = 0; i < h.Division.oddTerms.length; i++)
{
entityName=h.Division.oddTerms[i].entity; // "Sunshine"
terms = h.Division.oddTerms[i][entityName];
for (var j = 0; j < terms.length; j++) {
arrTerms.push('"' + terms[j].entity + '"');
}
}
// This will give you '{"Sunshine":["Dodge","Dodge Avenger"]}':
console.log(outputTemplate.replace('%entityName', entityName).replace('%terms', arrTerms.join(",")));
Edit:
Just some more on this.
JSON can be a bit confusing to work with if you're not used to working with JS and object and array "literals". In JS you can define objects and arrays in a number of ways, but the easiest (and the most preferred, by many developers) is with these literals.
Here's an example of an object:
var myObj = {
"some prop":"some value",
"anotherProp":"another value"
}
You can look up the members of myObj in several ways:
myObj.anotherProp // "another value"
myObj["some prop"] // you have to use this form if the property name has a space in it
For looping through the contents of an array, use the second form. For example, this won't work:
for (var strPropName in myObj) {
console.log(myObj.strPropName); // This won't work!
}
Instead, you should loop through the properties like this:
for (var strPropName in myObj) {
if (myObj.hasOwnProperty(strPropName)) {
console.log(myObj[strPropName]);
}
}
The if block is optional, but you'll avoid potential problems if you always include this in your code. It's also required by some validators.
Now, here's an example of an array:
var myArray = ["some value", "anotherValue"];
You access these with a numeric index:
myArray[0] // "some value"
myArray[1] // "anotherValue"
myArray[2] // undefined
And you can loop through them:
for (var index = 0; index < myArray.length; index++) {
console.log(myArray[index]);
}
You can nest objects inside arrays:
myArray = [{},{},{}];
And you can nest arrays inside objects:
myObject = {"arr1":[], "arr2":[], "arr3":[]}
{
"fulltime": [
{"name": "oscar godson", "age": "20", "email": "oscargodson#hismail.com"},
{"name": "daniel erickson", "age": "25", "email": "daniel#wraithtech.com"},
{"name": "john doe", "age": "18", "email": "john.doe#mycompany.com"}
],
"parttime":[
{"name": "bill johnson", "age": "35", "email": "billjohnson#gmail.com"}
]
}
and not knowing any of these values, e.g. fulltime could equal any thing. im looking for a function/method to loop through it all... Please, no jQuery.
Also, i want to basically get the output of: fulltime -> all inside of fulltime, parttime -> all inside of parttime, etc
for (key in your_object) {
console.log(key + " people:");
// "key" is "fulltime", "parttime", etc
for (var i = 0; i < your_object[key].length; i++) {
console.log(your_object[key][i]);
}
}
Supposing you have Firebug installed:
for(var key in json) {
//"fulltime", "parttime"
console.log("Checking " + key);
for(var i = 0; i < json[key].length; i++){
var person = json[key][i];
//Each person
for(var prop in person) {
console.log(prop + ": " + person[prop]);
}
}
}
Edit: Be careful that you don't iterate with for ... in ... over an array. To iterate over an array, use the "regular" way with for(var i = 0; i < array.length; i++){...}
You can do that with a recursive function. But you need to be careful about circular references. See example below:
var arr = [];
/**
* Gets the string representation of the specified object. This method is
* used for debugging
* #param {Object} Object to convert to string
* #return {String} The string representation of the object
*/
var toObjectSource = function(obj) {
if(obj === null) {
return "[null]";
}
if(obj === undefined) {
return "[undefined]";
}
var str = "[";
var member = null;
for(var each in obj) {
try {
member = obj[each];
if(arr.indexOf(member) === -1) { // the indexOf function is not available
// on older versions of js
arr.push(member);
str += each + "=" + toObjectSource(member) + ", "; // but beware of this
// recursive call!!!
}
}catch(err) {
alert(err);
}
}
return str + "]";
}
The reason for the check is that. It will give you "too much recursion" in case the object is like this:
var obj = {
"a": "a",
"b": "b"
}
obj.c = obj;
First of all you can verify your JSON data in http://www.jsonlint.com/.
If you not yet convert the string with JSON to the object you should use JSON.parse function from the web browser or from http://www.json.org/js.html to convert input string to the object.
For looping through the properties of a object you can use "for in" loop. It is generally always recommended to use this loop in the following form:
for (var name in myObject) {
if (myObject.hasOwnProperty(name)) {
// ....
}
}
(see for example http://www.jslint.com/lint.html#forin for the explanation). You should don't forget to declare name as var name either inside of for statement or somewhere before. If you forget this the variable will be interpret as a global and your code will run slowly.
Loop through element of an array in more effective with a standard for loop instead of "for in" loop. Moreover to receive more performance advantages you should always cache an index of a property used more as one time in a local variable. For example the the loop
for (var i = 0; i < your_object[key].length; i++) {
console.log(your_object[key][i]);
}
should be better rewritten as following:
var arr = your_object[key];
var len = arr.length;
for (var i = 0; i < len; i++) {
console.log(arr[i]);
}