Objects within an Array - javascript

I have multiple objects like the one below, and I was wondering what the correct syntax would be for putting them all within a single array. I'm also wondering how to correctly cycle through all of the arrays.
var verbMap = [
{
infinitive: "gehen",
thirdPres: "geht",
thirdPast: "ging",
aux: "ist",
pastPart: "gegangen",
english: "go"
},
{
infinitive: "gelingen",
thirdPres: "gelingt",
thirdPast: "gelang",
aux: "ist",
pastPart: "gelungen",
english: "succeed"
}
];
I know the correct way to cycle through that above array is:
for(v in verbMap){
for(p in verbMap[v]){
}
}
If I wanted to cycle through a larger array holding multiple arrays like verbMap, what would be the correct way to do that?

Just put the verbMap arrays in another array.
var verbMaps = [verbMap1, verbMap2...]
The key thing to understand is that your verbMap is an array of object literals. Only use
for (k in verbMap)...
for object literals.
The correct way to loop thru an array is something like
for (var i = 0; i < verbMaps.length; i++) {
var currentVerbMap = verbMaps[i];
for (var j = 0; j < currentVerbMap.length; j++) {
var currentHash = currentVerbMap[j];
for (var k in currentHash) {
console.log(k, currentHash[k];
}
}
}

The following function outputs every value from a (possibly) infinite array given as a parameter.
function printInfiniteArray(value){
if (value instanceof Array){
for(i=0;i<value.length;i++){
printInfiniteArray(value[i]);
}
} else {
console.log(value);
}
}
Edited code. Thanks jtfairbank

Your array does not contain other arrays. It contains objects. You could try this to loop though it.
for(var i = 0; i < verbMap.length; i++)
{
var obj = verbMap[i];
alert("Object #"+ i " - infinitive: " + obj.infinitive);
}

You would treat the array like any other javascript object.
var arrayOfArrays = [];
var array1 = ["cows", "horses", "chicken"];
var array2 = ["moo", "neigh", "cock-adoodle-doo"];
arrayOfArrays[0] = array1;
arrayOfArrays[1] = array2;
You can also use javascript's literal notation to create a multi-dimentional array:
var arrayOfArrays = [ ["meat", "veggies"], ["mmmm!", "yuck!"] ];
To cycle through the array of arrays, you'll need to use nested for loops, like so:
for (var i = 0; i < arrayOfArrays.length; i++) {
var myArray = arrayOfArrays[i];
for (var j = 0; j < myArray.length; j++) {
var myData = myArray[0]; // = arrayOfArrays[0][0];
}
}
DO NOT USE For...in!!!
That is not what it was made for. In javascript, For...in can have some unwanted behaviors. See Why is using "for...in" with array iteration a bad idea? for more detail.

You can use jQuery.each to cycle through an array or object, without having to check which one it is. A simple recursive function to cycle through key-value pairs in a nested structure, without knowing the exact depth:
var walk = function(o) {
$.each(o, function(key, value) {
if (typeof value == 'object') {
walk(value);
} else {
console.log(key, value);
}
});
}

Related

Modify an array of dictionaries, to add an element in each

How could I add an additional key value pair to each element in the following array.
get_project_list.completed = [{"user":"xyz","email":"a#123.com"}]
for (var i in get_project_list.completed) {
i['status'] = "completed";
}
O/P [{"user":"xyz","email":"a#123.com","status":"completed"}]
There should be a simple solution to this but couldn't find one which worked.
Any help is appreciated.
Don't use for in loop for arrays, because it iterates over every enumerable property.
For example here I add to the array a new property, which is enumerable and in the for in loop I get it also.
var arr = [{"user":"xyz","email":"a#123.com"}];
Object.defineProperty(arr, 'custom', { value: 'myCustom', enumerable: true });
for(let prop in arr){
console.log(prop);
}
If you are using ES6 you can do via
1) forEach function
var arr = [{"user":"xyz","email":"a#123.com"}];
arr.forEach(item => item['status'] = 'completed');
console.log(arr);
2) for of loop
var arr = [{"user":"xyz","email":"a#123.com"}];
for(let item of arr){
item['status'] = 'completed';
}
console.log(arr);
With ES5, you can use simple for loop
var arr = [{"user":"xyz","email":"a#123.com"}];
for(var i = 0; i < arr.length; i++){
arr[i]['status'] = 'completed'; // get the current index-th item
}
console.log(arr);
You get the index in the for loop and need to use it together with the array.
get_project_list.completed[i]['status'] = "completed";
// ^^^^^^^^^^^^^^^^^^^^^^^^^^
var get_project_list = { completed: [{"user":"xyz","email":"a#123.com"}] },
i;
for (i in get_project_list.completed) {
get_project_list.completed[i]['status'] = "completed";
}
console.log(get_project_list);
For arrays, I suggest to use a for loop with a counter, because you get all enumerable properties and the order is not guaranteed.
var get_project_list = { completed: [{"user":"xyz","email":"a#123.com"}] },
i;
for (i = 0; i <get_project_list.completed.length; i++) {
get_project_list.completed[i]['status'] = "completed";
}
console.log(get_project_list);
If you're transpiling (e.g. with Babel), I'd suggest using a map function in combination with the object spread operator instead.
let newList = get_project_list.completed.map(i =>
{... i, status : "completed" }
)
This way, you don't have to mutate the old array.

Remove data from an array comparing it to an other array

I am trying to compare the items in "item" array and the copyofOpList array to retrieve the data occurrences in copyofOpList
this is my try:
var _deleteUsedElement1 = function(item) {
for (var i = 0; i < item.length-1; i++){
for (var j = 0; j< $scope.copyofOpList.length-1; j++){
if (item[i].operationCode == $scope.copyofOpList[j].code) {
$scope.copyofOpList.splice(j, 1);
} } } };
$scope.compareArrays = function() {
...Get data from web Service
_deleteUsedElement1(item);
}
the copyofOpList array has 14 elements,and the item array has 2 array
but my code deletes only one occurrence (the first),so please how can I correct my code,to retrieve any occurances in the copyofOpList array comparing to the item array
thanks for help
I'd try to avoid looping inside a loop - that's neither a very elegant nor a very efficient way to get the result you want.
Here's something more elegant and most likely more efficient:
var item = [1,2], copyofOpList = [1,2,3,4,5,6,7];
var _deleteUsedElement1 = function(item, copyofOpList) {
return copyofOpList.filter(function(listItem) {
return item.indexOf(listItem) === -1;
});
};
copyofOpList = _deleteUsedElement1(item, copyofOpList);
console.log(copyofOpList);
//prints [3,4,5,6,7]
}
And since I just noticed that you're comparing object properties, here's a version that filters on matching object properties:
var item = [{opCode:1},{opCode:2}],
copyofOpList = [{opCode:1},{opCode:2},{opCode:3},{opCode:4},{opCode:5},{opCode:6},{opCode:7}];
var _deleteUsedElement1 = function(item, copyofOpList) {
var iOpCodes = item.map(function (i) {return i.opCode;});
return copyofOpList.filter(function(listItem) {
return iOpCodes.indexOf(listItem.opCode) === -1;
});
};
copyofOpList = _deleteUsedElement1(item, copyofOpList);
console.log(copyofOpList);
//prints [{opCode:3},{opCode:4},{opCode:5},{opCode:6},{opCode:7}]
Another benefit of doing it in this manner is that you avoid modifying your arrays while you're still operating on them, a positive effect that both JonSG and Furhan S. mentioned in their answers.
Splicing will change your array. Use a temporary buffer array for new values like this:
var _deleteUsedElement1 = function(item) {
var _temp = [];
for (var i = 0; i < $scope.copyofOpList.length-1; i++){
for (var j = 0; j< item.length-1; j++){
if ($scope.copyofOpList[i].code != item[j].operationCode) {
_temp.push($scope.copyofOpList[j]);
}
}
}
$scope.copyofOpList = _temp;
};

Javascript - nested loops and indexes

I am trying to build an array that should look like this :
[
[{"name":"Mercury","index":0}],
[{"name":"Mercury","index":1},{"name":"Venus","index":1}],
[{"name":"Mercury","index":2},{"name":"Venus","index":2},{"name":"Earth","index":2}],
...
]
Each element is the concatenation of the previous and a new object, and all the indexes get updated to the latest value (e.g. Mercury's index is 0, then 1, etc.).
I have tried to build this array using the following code :
var b = [];
var buffer = [];
var names = ["Mercury","Venus","Earth"]
for (k=0;k<3;k++){
// This array is necessary because with real data there are multiple elements for each k
var a = [{"name":names[k],"index":0}];
buffer = buffer.concat(a);
// This is where the index of all the elements currently in the
// buffer (should) get(s) updated to the current k
for (n=0;n<buffer.length;n++){
buffer[n].index = k;
}
// Add the buffer to the final array
b.push(buffer);
}
console.log(b);
The final array (b) printed out to the console has the right number of objects in each element, but all the indexes everywhere are equal to the last value of k (2).
I don't understand why this is happening, and don't know how to fix it.
This is happening because every object in the inner array is actually the exact same object as the one stored in the previous outer array's entries - you're only storing references to the object, not copies. When you update the index in the object you're updating it everywhere.
To resolve this, you need to create new objects in each inner iteration, or use an object copying function such as ES6's Object.assign, jQuery's $.extend or Underscore's _.clone.
Here's a version that uses the first approach, and also uses two nested .map calls to produce both the inner (variable length) arrays and the outer array:
var names = ["Mercury","Venus","Earth"];
var b = names.map(function(_, index, a) {
return a.slice(0, index + 1).map(function(name) {
return {name: name, index: index};
});
});
or in ES6:
var names = ["Mercury","Venus","Earth"];
var b = names.map((_, index, a) => a.slice(0, index + 1).map(name => ({name, index})));
Try this:
var names = ["Mercury","Venus","Earth"];
var result = [];
for (var i=0; i<names.length; i++){
var _temp = [];
for(var j=0; j<=i; j++){
_temp.push({
name: names[j],
index:i
});
}
result.push(_temp);
}
console.log(result)
try this simple script:
var b = [];
var names = ["Mercury","Venus","Earth"];
for(var pos = 0; pos < names.length; pos++) {
var current = [];
for(var x = 0; x < pos+1; x++) {
current.push({"name": names[x], "index": pos});
}
b.push(current);
}

Check whether an object with property value 'x' exists in an array in Javascript

I have a lot of objects that I'm trying to filter out duplicates from. When an object has a property, IMAGEURL which is present in another object, I want to ignore this object and move on.
I'm using nodeJS for this so if there's a library I can use to make it easier let me know.
I've done similar implementations before with checking string values in arrays, doing something like:
var arr = ['foo', 'bar'];
if(arr.indexOf('foo') == -1){
arr.push('foo')
}
But this won't work for objects, as best I can tell. What are my options here? To put it more simply:
var obj1 = {IMAGEURL: 'http://whatever.com/1'};
var obj2 = {IMAGEURL: 'http://whatever.com/2'};
var obj3 = {IMAGEURL: 'http://whatever.com/1'};
var arr = [obj1, obj2, obj3];
var uniqueArr = [];
for (var i = 0; i<arr.length; i++){
// For all the iterations of 'uniqueArr', if uniqueArr[interation].IMAGEURL == arr[i].IMAGEURL, don't add arr[i] to uniqueArr
}
How can I do this?
You can just use an inner loop (keeping track of whether we've seen the loop by using a seen variable -- you can actually use labels here, but I find the variable method to be easier to read):
for (var i = 0; i<arr.length; i++){
var seen = false;
for(var j = 0; j != uniqueArr.length; ++j) {
if(uniqueArr[j].IMAGEURL == arr[i].IMAGEURL) seen = true;
}
if(!seen) uniqueArr.push(arr[i]);
}
Here is a concise way:
var uniqueArr = arr.filter(function(obj){
if(obj.IMAGEURL in this) return false;
return this[obj.IMAGEURL] = true;
}, {});
http://jsfiddle.net/rneTR/2
Note: this is concise, but orders of magnitude slower than Nirk's answer.
See also: http://monkeyandcrow.com/blog/why_javascripts_filter_is_slow/

javascript array with numeric index without undefineds

suppose I do..
var arr = Array();
var i = 3333;
arr[i] = "something";
if you do a stringify of this array it will return a string with a whole bunch of undefined numeric entries for those entries whose index is less than 3333...
is there a way to make javascript not do this?
I know that I can use an object {} but I would rather not since I want to do array operations such as shift() etc which are not available for objects
If you create an array per the OP, it only has one member with a property name of "333" and a length of 334 because length is always set to be at least one greater than the highest index. e.g.
var a = new Array(1000);
has a length of 1000 and no members,
var a = [];
var a[999] = 'foo';
has a length of 1000 and one member with a property name of "999".
The speedy way to only get defined members is to use for..in:
function myStringifyArray(a) {
var s = [];
var re = /^\d+$/;
for (var p in a) {
if (a.hasOwnProperty(p) && re.test(p)) {
s.push(a[p]);
}
}
return '' + s;
}
Note that the members may be returned out of order. If that is an issue, you can use a for loop instead, but it will be slower for very sparse arrays:
function myStringifyArray(a) {
var s = [];
var re = /^\d+$/;
for (var i=0, iLen=a.length; i<iLen; i++) {
if (a.hasOwnProperty(i)) {
s.push(a[i]);
}
}
return '' + s;
}
In some older browsers, iterating over the array actually created the missing members, but I don't think that's in issue in modern browsers.
Please test the above thoroughly.
The literal representation of an array has to have all the items of the array, otherwise the 3334th item would not end up at index 3333.
You can replace all undefined values in the array with something else that you want to use as empty items:
for (var i = 0; i < arr.length; i++) {
if (typeof arr[i] == 'undefined') arr[i] = '';
}
Another alternative would be to build your own stringify method, that would create assignments instead of an array literal. I.e. instead of a format like this:
[0,undefined,undefined,undefined,4,undefined,6,7,undefined,9]
your method would create something like:
(function(){
var result = [];
result[0] = 0;
result[4] = 4;
result[6] = 6;
result[7] = 7;
result[9] = 9;
return result;
}())
However, a format like that is of course not compatible with JSON, if that is what you need.

Categories

Resources