I have this Js method but I can't to implement a reverse loop
$scope.organizeByMonth = function () {
for (var i in $scope.incidents) {
var month = new Date($scope.incidents[i].upload_date).getMonth();
if (!monthIncidents[month]) {
monthIncidents[month] = {
name: $scope.months[month],
incidents: []
};
}
var incident = $scope.incidents[i];
incident.index = i;
monthIncidents[month].incidents.push(incident);
}
};
how can I show the same objects in reverse :/
You can't do a reverse loop with the for in syntax - it also doesn't matter. Objects in JavaScript are unordered.
The closest to a reverse for..in.. loop would be to get the object keys and iterate backwards over them:
var object = { a: 1, b: 2, c: 3 };
var keys = Object.keys(object);
for(var i = keys.length - 1; i >= 0; i--) {
console.log(keys[i], object[keys[i]]);
}
http://jsfiddle.net/1oztmp2e/
Why would you like to reverse the for loop? Is it only for display purpose?
If so, I am assuming you are using ng-repeat for displaying the records. Should that be the case, you can use a custom reverse filter.
Or if you need the array reversed for a different reason, simply use Array.reverse after populating the array
Related
I have an situation where I have 3 different arrays with very different amounts of objects in it. I've read many questions and blog posts about this but Im still unsure when to use what.
PS! My biggest problem is that I need to iterate and push (perfect for arrays), also find if exists in array and delete (more suitable for objects). Specific order is not required.
I can't allow having same object in both array1 and array1clicked
because they should perform different actions.
When it's best to use object and when array in my example? What should I replace with object and what should stay as array? Im pretty sure that amounts of objects in it also matters, right?
My current code:
//Objects in arrays are literally custom {objects} with custom prototypes and html
var array1 = [ 20 objects ];
var array1clicked = [];
var array2 = [ 250 objects ];
var array2clicked = [];
var array3 = [ 50 000 objects ];
var array3clicked = [];
//Each object in arrays has event attached
objecthtml.click(function() {
//Add to clicked array
array1clicked.push(thisobject);
//Remove from initial array
var index = array1.indexOf(thisobject);
if (index > -1) {
array1.splice(index, 1);
}
}
//Same with array2 and array3 objects
//Iterations on different conditions
var array1count = array1.length;
var array1clickedcount = array1clicked.length;
//Same with array2 and array3
if(condition1) {
for(a = 0; a < array1count; a++) {
array1[a].div.style.visibility = 'hidden';
}
//Same with array2 and array3 objects
for(a = 0; a < array1clickedcount; a++) {
array1clicked[a].div.style.visibility = 'visible';
}
//Same with array2clicked and array3clicked objects
}
else if(condition2) {
for(a = 0; a < array1count; a++) {
array1[a].div.style.visibility = 'visible';
}
//Same with array2 and array3 objects
for(a = 0; a < array1clickedcount; a++) {
array1clicked[a].div.style.visibility = 'hidden';
}
//Same with array2clicked and array3clicked objects
}
It seems you want a data structure with these operations:
Iteration
Insert
Delete
Search
With arrays, the problem is that searches and deletions (with reindexing) are slow.
With objects, the problem is that the property names can only be strings.
The perfect structure is a set.
var s = new Set();
s.add(123); // insert
s.has(123); // search
s.delete(123); // delete
s.values(); // iterator
In your case, I think you have to use just Array.
In common case, you could use object to keep references and push some values into it, but If you wanna iterate on this, I think you have to use Array.
I have an array of objects which contain certain duplicate properties: Following is the array sample:
var jsonData = [{x:12, machine1: 7}, {x:15, machine2:7},{x:12, machine2: 8}];
So what i need is to merge the objects with same values of x like the following array:
var jsonData = [{x:12, machine1:7, machine2:8}, {x:15, machine2:7}]
I like the lodash library.
https://lodash.com/docs#groupBy
_.groupBy(jsonData, 'x') produces:
12: [ {x=12, machine1=7}, {x=12, machine2=8} ],
15: [ {x=15, machine2=7} ]
your desired result is achieved like this:
var jsonData = [{x:12, machine1: 7}, {x:15, machine2:7},{x:12, machine2: 8}];
var groupedByX = _.groupBy(jsonData, 'x');
var result = [];
_.forEach(groupedByX, function(value, key){
var obj = {};
for(var i=0; i<value.length; i++) {
_.defaults(obj, value[i]);
}
result.push(obj);
});
I'm not sure if you're looking for pure JavaScript, but if you are, here's one solution. It's a bit heavy on nesting, but it gets the job done.
// Loop through all objects in the array
for (var i = 0; i < jsonData.length; i++) {
// Loop through all of the objects beyond i
// Don't increment automatically; we will do this later
for (var j = i+1; j < jsonData.length; ) {
// Check if our x values are a match
if (jsonData[i].x == jsonData[j].x) {
// Loop through all of the keys in our matching object
for (var key in jsonData[j]) {
// Ensure the key actually belongs to the object
// This is to avoid any prototype inheritance problems
if (jsonData[j].hasOwnProperty(key)) {
// Copy over the values to the first object
// Note this will overwrite any values if the key already exists!
jsonData[i][key] = jsonData[j][key];
}
}
// After copying the matching object, delete it from the array
// By deleting this object, the "next" object in the array moves back one
// Therefore it will be what j is prior to being incremented
// This is why we don't automatically increment
jsonData.splice(j, 1);
} else {
// If there's no match, increment to the next object to check
j++;
}
}
}
Note there is no defensive code in this sample; you probably want to add a few checks to make sure the data you have is formatted correctly before passing it along.
Also keep in mind that you might have to decide how to handle instances where two keys overlap but do not match (e.g. two objects both having machine1, but one with the value of 5 and the other with the value of 9). As is, whatever object comes later in the array will take precedence.
const mergeUnique = (list, $M = new Map(), id) => {
list.map(e => $M.has(e[id]) ? $M.set(e[id], { ...e, ...$M.get(e[id]) }) : $M.set(e[id], e));
return Array.from($M.values());
};
id would be x in your case
i created a jsperf with email as identifier: https://jsperf.com/mergeobjectswithmap/
it's a lot faster :)
I want to create an array in javascript to have 20 elements with a starting index of 15, assign every element with a value of 00000. What is the most efficient way, and can it be done without looping through the index?
TIA.
Array indexes in javascript are always in the interval [0, num_elements). If you do not want this, you need to use an object. Then you have arbitraty indexes but no fixed order.
Without loop you can only use instant initialization:
var arr = [null, null, null, ... 15 times ...., '000000', '000000', '000000', '000000', '000000'];
But probably it's better to use loop :)
It's better to use an object, if you want to use an offset:
var iOffset = 15;
var iCount = 20;
var oValues = {};
for (var i = iOffset ; i < iOffset + iCount; i++) {
oValues[i] = 0;
}
For the specific case where each item in the array is a string, you can do it without a loop with the new Array(length) constructor and a sneaky join:
new Array(15).concat(('000000'+new Array(20).join(',000000')).split(','))
Unlikely to be faster than the loop though... certainly less clear. I'd also question whether an Array with missing properties 0–14 is something it's generally sensible to have.
You can't have an array starting with an index of 15. The index of an array always start with index 0, as is demonstrated with:
var a = [];
a[15] = '000';
alert(a.length); //=> 16
You could use a recursive function to create an array of 20 elements, something like:
function arr(len){
return len ? arr(len-1).concat('0000') : [];
}
var myArr = arr(20);
Or create an array of small objects, containing your custom index:
function arr(len){
return len ? arr(len-1).concat({index:len+14,value:'0000'}) : [];
}
var myArr = arr(20);
alert(myArr[0].index); //=> 15
Alternatively, using a loop, you can do something like:
var nwArr = function(len,start){
var l = len+start, a = Array(l);
while ((l-=1)>=start){ a[l] = '0000'; }
return a;
}(20,15);
alert(nwArr[15]); //=> '0000'
alert(nwArr[0]); //=> undefined
I usually script/program using python but have recently begun programming with JavaScript and have run into some problems while working with arrays.
In python, when I create an array and use for x in y I get this:
myarray = [5,4,3,2,1]
for x in myarray:
print x
and I get the expected output of:
5
4
3
..n
But my problem is that when using Javascript I get a different and completely unexpected (to me) result:
var world = [5,4,3,2,1]
for (var num in world) {
alert(num);
}
and I get the result:
0
1
2
..n
How can I get JavaScript to output num as the value in the array like python and why is this happening?
JavaScript and Python are different, and you do things in different ways between them.
In JavaScript, you really should (almost) always iterate over an array with a numeric index:
for (var i = 0; i < array.length; ++i)
alert(array[i]);
The "for ... in" construct in JavaScript gives you the keys of the object, not the values. It's tricky to use on an array because it operates on the array as an object, treating it no differently than any other sort of object. Thus, if the array object has additional properties — which is completely "legal" and not uncommon — your loop will pick those up in addition to the indexes of the "normal" array contents.
The variable num contains the array item's index, not the value. So you'd want:
alert(world[num])
to retrieve the value
The for var in... loop in JavaScript puts the keys in the variable instead of the actual value. So when using for var ... you should do something like this:
var world = [5, 4, 3, 2, 1];
for ( var key in world ) {
var value = world[key];
alert(key + " = " + value);
}
And note that this way of looping is best used when you're using objects instead of arrays. For arrays use the common:
for ( var i = 0, j = arr.length; i < j; i++ ) { ... }
Or if you're targeting modern browser you can use the forEach-method of arrays:
var arr = [1, 2, 3];
arr.forEach(function(num) {
alert(num);
});
The for...in loop loops over all key elements; not the values.
I would recommend you to use
for(var i=0; i<arr.length; i++){
alert(arr[i]);
}
When you use the in operator num becomes a key. So simply use this key to get a value out of the array.
var world = [5,4,3,2,1]
for (var num in world) {
alert(world[num]);
}
try this.
var world = [5,4,3,2,1]
for(var i=0;i<world.length;i++){
alert(world[i])
}
Because javascript in your case is printing the index of the element, not the value.
the result you got is just element index,if you want to get element value
your code should like this
var world = [5,4,3,2,1]
for (var num in world) {
alert(world[num]);
}
The for in iteration in JavaScript works only for the object data type. The way it works is that it lets you iterate over the attributes of an object. arrays are objects in JavaScript, but the for in only works on its attributes, not the array values.
For example you might define an array as such:
var arr = [1,2,3];
And you can assign attributes to this array, because it's actually an object:
arr.foo = "bar";
arr["1"] = 2;
Now when you use the for in iteration method you will be able to iterate over the attributes we just assigned above;
for(var i in arr) console.log(i);
To iterate over the actual array values you need to use the for(var i=0; i<arr.length; i++) construct.
Hope this helps.
In javascript it's advised to loop Arrays different from looping Objects. You are using an object loop, which may return unexpected result (for instance if the Array.prototype was extended with custom methods you would iterate those too, and it does't guarantee the order of the array is preserved). There are many ways to loop through an array, using it's index:
// regular
var arr = [1,2,3,4,5]
,i
;
for (i=0;i<arr.length;i++) {
console.log(arr[i]);
}
// using while
var arr = [1,2,3,4,5]
,i = 0
;
while ((i = i + 1)<arr.length) {
console.log(arr[i]);
}
// using while reversed
var arr = [1,2,3,4,5]
,i = arr.length
;
while ((i = i - 1) > -1) {
console.log(arr[i]);
}
Note: Why not use i++ or i--? To avoid confusion, index out of range-errors and to satisfy JSLint
Considering this data structure:
var vehicles = [
[ "2011","Honda","Accord" ],
[ "2010","Honda","Accord" ],
.....
];
Looping through each vehicles item, is there a way to reassign the array elements to individual variables all in one shot, something like:
for (i = 0; i < vehicles.length; i++) {
var(year,make,model) = vehicles[i]; // doesn't work
.....
}
... I'm trying to get away from doing:
for (i = 0; i < vehicles.length; i++) {
var year = vehicles[i][0];
var make = vehicles[i][1];
var model = vehicles[i][2];
.....
}
Just curious since this type of thing is available in other programming languages. Thanks!
Now it is possible using ES6's Array Destructuring.
As from Docs:
The destructuring assignment syntax is a JavaScript expression that makes it possible to unpack values from arrays, or properties from objects, into distinct variables.
Consider the following example:
let [a, b, c] = [10, 20, 30];
console.log(a); // output => 10
console.log(b); // output => 20
console.log(c); // output => 30
As with your data, .forEach() method can also be used for iterating over array elements along with Array Destructuring:
let vehicles = [
[ "2011","Honda","Accord" ],
[ "2010","Honda","Accord" ]
];
vehicles.forEach(([year, make, model], index) => {
// ... your code here ...
console.log(`${year}, ${make}, ${model}, ${index}`);
});
References:
Array Destructuring
Array.prototype.forEach()
Arrow Functions
Template Literals
No unfortunately there is not a method to do this currently XBrowser. (that I'm aware of).
Relatively soon it's possible cross browser, see link:
https://developer.mozilla.org/en/New_in_JavaScript_1.7
(In PHP there is "list" which will do exactly what you wish, nothing similar XBrowser for javascript yet)
Of course relatively soon could mean anything etc. (Thanks Felix for pointing out my errors in this)
edit: This is now available see: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment#Array_destructuring
Probably the closest you'll currently get in javascript is to eliminate the redundant var and separate the statements with a comma separator.
for (i = 0; i < vehicles.length; i++) {
var year = vehicles[i][0], make = vehicles[i][1], model = vehicles[i][2];
.....
}
or you could shorten it a bit more like this:
for (i = 0; i < vehicles.length; i++) {
var v = vehicles[i], year = v[0], make = v[1], model = v[2];
.....
}
The closest alternative that I could think of is using a function and using apply() to call it. Passing an array, it would get passed as each argument.
function vehicle(year, make, model) {
// do stuff
}
for (i = 0; i < vehicles.length; i++) {
vehicle.apply (this, vehicles[i]);
}
Or an anonymous function:
for (i = 0; i < vehicles.length; i++) {
(function(year, make, model) {
// do stuff
}).apply(this, vehicles[i]);
}
Unpacking array into separate variables in JavaScript
The destructuring assignment syntax is a JavaScript expression that
makes it possible to unpack values from arrays, or properties from objects,into distinct variables.
let array = [2,3];
[a,b] = array;// unpacking array into var a and b
console.log(a); //output 2
console.log(b); //output 3
let obj = {name:"someone",weight:"500pounds"};
let {name,weight} = obj; // unpacking obj into var name and weight
console.log(name);// output someone
console.log(weight);//output 500pounds
Source