vm.categorias = function () {
ConectaVagas('get', 'categorias').then(function (val) {
vm.categorias = val;
for (var a = 0; a < vm.categorias.length; a++) {
console.log(a); // Here returns 0,1,2,3 ( number with categories )
ConectaVagas('get', 'subcategoria', vm.categorias[a].id_categoria).then(function (val) { // List the subcategories related the categorie in loopfor
vm.subAplicar = val;
console.log(a); // Here returns the number 4 but i want returns 0, 1, 2, 3 and i do the insertion in arrayNova
vm.categoria[a].arrayNova = vm.subAplicar;
});
}
});
}
I need to insert into the object vm.category [a] an array (arrayNova) with all subcategories, but I am not following :(
You need to enclose in a new function the second call to ConnectVagas. Your variable a always prints to 4, because in javascript variables have a function scope. In order to correct this, create an anonymous function with parameters the current_item and a, so the value of a will not get overwritten because it creates a new function scope.
vm.categorias = function() {
ConectaVagas('get', 'categorias').then(function(val) {
vm.categorias = val;
for (var a = 0; a < vm.categorias.length; a++) {
console.log(a); // Here returns 0,1,2,3 ( number with categories )
var categorias_item = vm.categorias[a].id_categoria
(function(categorias_item, a) {
ConectaVagas('get', 'subcategoria', categorias_item.id_categoria).then(function(val) { // List the subcategories related the categorie in loopfor
vm.subAplicar = val;
console.log(a); // Here returns the number 4 but i want returns 0, 1, 2, 3 and i do the insertion in arrayNova
categorias_item.arrayNova = vm.subAplicar;
});
})(categorias_item, a);
}
});
}
Related
I was trying to find as a dictionary (JS object) how many times each of the elements appears in some list. For example, the appearance of 1 in the list [1,1,2,2,1,3,4] is 3, because there are three ones in the list. In python I would implement this in the following way:
l = [1,1,2,2,1,3,4]
apr = dict()
for e in l:
if (e in apr.keys()):
apr[e] += 1
else:
apr[e] = 1
In javascript I decided to do
var arr = [1,1,2,2,1,3,4];
var vals = {};
for (let e of arr){
if (e in Object.keys(vals)){
vals[e] = vals[e] + 1;
}
else{
vals[e] = 1;
}
}
// vals = { '1': 2, '2': 1, '3': 1, '4': 1 }
which is obviously wrong. Then I tried if (Object.keys(vals).includes(e)){ instead, and it didn't work either. At the very end I implemented my own function my_in, and the progem worked:
function my_in(val,arr){
for (i = 0; i<=arr.length; i++){
if (val==arr[i]){
return true;
}
}
return false;
}
var arr = [1,1,2,2,1,3,4];
var vals = {};
for (let e of arr){
//if (Object.keys(vals).includes(e)){
// if (e in Object.keys(vals)){
if (my_in(e, Object.keys(vals))) {
vals[e] = vals[e] + 1;
}
else{
vals[e] = 1;
}
}
console.log(vals);
But I am still confused why did the first two tries didn't work. Is there anything I should be aware of when using in or includes()?
You need to use in operator with the object, not with an array this would check the indices.
For example by using an an array of keys
vals = { 1: 1 }
keys = Object(vals) // ['1']
if (1 in keys) performs
-> 1 in { 0: 1, length: 1 }, because there is only index zero with value one
-> false
var arr = [1, 1, 2, 2, 1, 3, 4];
var vals = {};
for (let e of arr) {
if (e in vals) { // check with object
vals[e] = vals[e] + 1;
} else {
vals[e] = 1;
}
}
console.log(vals);
The Object.keys(object) function returns an array of the string keys in the object.
When you do if (e in Object.keys(vals)) this would actually check the e element in the array returned from the Object.keys call. Which is not what you want.
You should simply check the presence of the e key in the vals object, if present increment by 1 else assign 0 to it:
var arr = [1,1,2,2,1,3,4];
var vals = {};
for (let e of arr){
vals[e] = (vals[e] || 0) + 1;
}
console.log(vals)
The issue with your code was, when you did Object.keys(vals) for the first iteration it returned an empty array [] as vals was an empty object {}. So e in Object.keys(vals) was false and it went to the else block. In the else block the vals[e] = 1 was executed.
In the next iteration when the check e in Object.keys(vals) happened it was evaluated to true as the array ["1"] was returned because vals is {1: 1}, same for the other elements so that is why you see {1: 2, 2: 1...}.
I would like to browse an associative array like a circular list.
First the associative array is defined like this :
array = {item1:array(...), item2:array(...), ...}
When at the first element I browse the array of this element, once arrive at the last element of this array it should passe to the second element and brows it's array, and the same for the last one who must return to the first element.
so I initialize my array as follows:
// Build the associative array
Prot.prototype.additem = function(itemName, itemArray)
{
this.array[itemName] = itemArray; // itemArray is an array
}
// Init the currentItem of the associative array to browse (We don't necessarily start at the first)
Prot.prototype.init = function(itemName)
{
this.currentItem = this.array[itemName];
this.currentItemArray = 0;
}
Prot.prototype.next = function()
{
// here I browse the first array of the first key of my associative array
var index = this.currentItem.indexOf(this.currentItemArray);
index = index +1;
this.currentItemArray = this.currentItem[index];
if (index == (this.currentItemArray.length - 1))
{
// when arrives at the last element of the array of the first key I should pass to the second
return false;
}
else {
return true;
}
}
// I add a set interval at the end so no need for a loop
You'll need an array to know what is the "next" item array. So I would suggest storing the desired order in another array, having just those names.
Here is a possible implementation:
class Prot {
constructor() {
this.itemNames = [];
this.arrays = {};
this.hasData = false;
this.currentIndex = 0;
}
additem(itemName, itemArray) {
if (itemName in this.arrays) throw "duplicate entry";
this.arrays[itemName] = { data: itemArray, index: this.itemNames.length };
this.itemNames.push(itemName); // keep the order
if (itemArray.length) this.hasData = true;
}
init(itemName) {
this.currentItem = this.arrays[itemName];
this.currentIndex = 0;
}
next() {
if (!this.hasData) return;
if (!this.currentItem) this.currentItem = this.arrays[this.itemNames[0]];
var data = this.currentItem.data[this.currentIndex++];
while (this.currentIndex >= this.currentItem.data.length) {
this.currentItem = this.arrays[this.itemNames[(this.currentItem.index+1) % this.itemNames.length]];
this.currentIndex = 0;
}
return data;
}
}
// demo
let obj = new Prot;
// add the arrays:
obj.additem("a", [1, 2, 3]);
obj.additem("b", [4, 5]);
obj.additem("c", [6, 7, 8, 9]);
obj.additem("d", [0]);
// Start at "b":
obj.init("b");
// iterate from there...
for (let i = 0; i < 12; i++) {
console.log(obj.next());
}
There is no such thing as an associative array in JavaScript, but you can use an object instead. A very simple implementation of defining an object and referencing its properties in a circular way would be the following:
// define the object with 6 properties and assiociated values:
var obj={a:123, b:456, c:789, d:666, e:777, f:888};
function getcirc(obj){
// use a "static variable" inside the function:
if(typeof getcirc.i=="undefined") getcirc.i=0;
var keys=Object.keys(obj), k=keys[getcirc.i++%keys.length];
console.log(k,obj[k]);
}
// call the function repeatedly ...
for (var n=0;n<20;n++) getcirc(obj);
If I call the filter function, I get this array returned [ 1, , 3, , 5 ]. From where come the additional commas? I don't understand this effect. Can somebody explain it to me?
The array should be that: [ 1, 3, 5 ].
class List {
constructor(values = []) {
this._list = values;
}
filter(func) {
let newList = new Array();
let indexList = 0;
let indexNewList = 0;
while (this._list[indexList] != undefined) {
if (func(this._list[indexList]) === true) {
newList[indexNewList] = this._list[indexList];
indexNewList++;
}
indexList++;
}
this._list = newList;
return this;
}
get values() { return this._list }
}
var isOdd = function (x) {
return x % 2 === 1;
};
var list = new List([1, 2, 3, 4, 5]);
console.log(list.filter(isOdd).values);
If an item in the list matches the filter, you're inserting it into the new list at the index of the item in the original list. You want to simply be appending the item to the new list.
Use another variable to keep track of what index the element should be inserted into the new list at:
let newList = new Array();
let indexList = 0;
let newIndex = 0;
while (this._list[indexList] != undefined) {
if (func(this._list[indexList]) === true) {
newList[newIndex] = this._list[indexList];
newIndex++;
}
indexList++;
}
The newIndex variable will only be incremented when an item has been inserted into newList, instead of being incremented with every iteration of the loop.
The problem is the increment of the variable index, that increment is creating empty/undefined elements.
For example:
Array = [1];
index = 1
callback returns false
The index is incremented by 1 -> index =2`
Next iteration callback returns true
A new element is added to Array at position 2 ->
Array = [1, undefined, 3].
Use a separated index for the newArray.
class List {
constructor(values = []) {
this._list = values;
}
filter(func) {
let newList = new Array();
let index = 0;
let newListIndex = 0;
while (this._list[index] != undefined) {
if (func(this._list[index]) === true) {
newList[newListIndex++] = (this._list[index]);
}
index++;
}
this._list = newList;
return this;
}
get values() {
return this._list
}
}
var isOdd = function(x) {
return x % 2 === 1;
};
var list = new List([1, 2, 3, 4, 5]);
console.log(list.filter(isOdd));
I would suggest sticking with a functional-programming style definition of array#filter since that is the paradigm it originates from.
This is the fully immutable version of List#filter where you get a new instance of List back and the underlying array never goes through any form of mutation.
class List {
constructor(values = []) {
this._list = values;
}
filter(func) {
var reduce = function(values, accum) {
if(values.length === 0) return accum;
if(func(values[0])) return reduce(values.slice(1), accum.concat(values[0]));
else return reduce(values.slice(1), accum)
}
return new List(reduce(this._list, []))
}
get values() {
return this._list
}
}
var isOdd = function(x) {
return x % 2 === 1;
};
var list = new List([1, 2, 3, 4, 5]);
console.log(list.filter(isOdd));
Write a function that takes in an object like so {1: 4, 2: 10, 5:3} and then return a list of all the numbers described in the object. Each key-value pair describes a number and how many times it should occur in the array.
Example:
{3 : 10,5 : 2}
[3,3,3,3,3,3,3,3,3,3,5,5]
Also account for empty, null, undefined and non-objects in your code that can be passed in
In those cases just return [], the empty list
Here's what I've been able to produce for. I know I have to do a second loop, but I don't understand how to make the numbers appear in the array the number of times described. Here's my progress:
var numObj = {1:4, 2:10, 3:5};
function numDescribed(numObj) {
var numOfNums = [];
for (var x in numObj) {
numOfNums.push(numObj[x]); //this produces an array of [4, 10, 5]
} for (var i = 0; i < numOfNums.length; i++) {
numOfNums.
}
}
var obj = { 3: 10, 5: 2 };
var res = [];
Object.keys(obj).forEach(function(e) {
for (var i = 0; i < obj[e]; i++) {
res.push(e);
}
});
document.write(res);
I would like to have an array based on Uint32Array. The length of the array should grow incrementally while amount of its elements grows. At the same time I want "length" property return the number of elements, not the size of the underlying array. For instance:
var a = new myArray();
a.length; // returns 0, the size of underlying array is 10
a.add(0);
a.length; // returns 1, the size of underlying array is 10
...
a.add(9);
a.length; // returns 10, the size of underlying array is 10
a.add(10);
a.length; // returns 11, the size of underlying array is 20
The code below shows how I tried to implement it. The only obstacle is the access to "length" property of the original array. The "parent" word in the code is only for the example. If I replace it with "this.prototype" it says "this.prototype.length" in undefined.
Is it possible to work around it?
var myArray = function() {
this._length = 0;
return this;
// defining the getter for "length" property
Object.defineProperty(this, "length", {
get: function() {
return this._length;
},
};
myArray.prototype = new Uint32Array(myArray.increment);
myArray.increment = 10;
myArray.add = function(val) {
if (this.length <= parent.length) {
_a = new Uint32Array(parent.length + myArray.increment);
_a.set(this);
this = _a;
};
this[this.length++] = val;
};
This is what I would do:
function MyArray(increment) {
var array = new Uint32Array(increment);
var length = 0;
Object.defineProperty(this, "length", {
get: function () {
return length;
}
});
this.add = function (value) {
if (length === array.length) {
var ext = new Uint32Array(length + increment);
ext.set(array);
array = ext;
}
var index = length++;
array[index] = value;
Object.defineProperty(this, index, {
get: function () {
return array[index];
},
set: function (value) {
array[index] = value;
}
});
};
}
Then you create your array as follows:
var a = new MyArray(10);
a.length; // returns 0, the size of underlying array is 10
a.add(0);
a.length; // returns 1, the size of underlying array is 10
...
a.add(9);
a.length; // returns 10, the size of underlying array is 10
a.add(10);
a.length; // returns 11, the size of underlying array is 20
You're doing inheritance in JavaScript wrong. Read about it here.
You can see the demo here: http://jsfiddle.net/dWKTX/1/