Can someone please explain me how to change template.portNumber value ?
var template = {
portNumber: null,
stuff: ""
}
myfunc(template, 3);
function myfunc(template, count) {
var ports = {}
for (var i = 0; i < count; i++) {
var portNumber = i + 1;
ports[portNumber.toString()] = template;
ports[portNumber.toString()].portNumber = portNumber;
}
console.debug(JSON.stringify(ports, null, 4));
return ports;
}
Result:
"{
"1": {
"portNumber": 3,
"stuff": ""
},
"2": {
"portNumber": 3,
"stuff": ""
},
"3": {
"portNumber": 3,
"stuff": ""
}
}"
Expected:
"{
"1": {
"portNumber": 1,
"stuff": ""
},
"2": {
"portNumber": 2,
"stuff": ""
},
"3": {
"portNumber": 3,
"stuff": ""
}
}"
Sorry for the stupid question but i really stuck with it. Same code works well in python.
Thanks.
Your array ends up having three references to the same object so each time you mutate it the change is visible in all array elements.
Writing ports[0].port = "99" will in other words change also ports[1].port because ports[0] and ports[1] are the very same object.
You need to create a copy of the object instead...
The reason all array object are reference type so point to only one instance.
Try using constructor function like this.
var template = function(portno, stf){
this.portNumber = portno;
this.stuff = stf;
}
myfunc(template, 3);
function myfunc(template, count) {
var ports = {}
for (var i = 0; i < count; i++) {
var portNumber = i + 1;
ports[portNumber.toString()] = new template(portNumber , template.stuff);
}
console.debug(JSON.stringify(ports, null, 4));
return ports;
}
The template object is passed by reference, so all the items refer to the same object. It ends up looking a little like this:
template = {portNumber: 3, stuff: ""};
return {ports: {1:template, 2: template, 3: template}}
You need to clone the object, and then set it.
var template = {
portNumber: null,
stuff: ""
}
myfunc(template, 3);
function myfunc(template, count) {
var ports = {}
for (var i = 0; i < count; i++) {
var portNumber = i + 1;
ports[portNumber] = JSON.parse(JSON.stringify(template));
ports[portNumber].portNumber = portNumber;
}
console.debug(JSON.stringify(ports, null, 4));
return ports;
}
Also, you don't need to manually stringify a numerical key, it's done automatically.
This is a reference problem.
console.log(myFunc(template, 3));
function myFunc(template, count) {
var ports = {}
for (var i = 0; i < count; i++) {
var portNumber = i + 1;
ports[portNumber.toString()] = {portNumber:null, stuff:""};
ports[portNumber.toString()].portNumber = portNumber;
}
// console.debug(JSON.stringify(ports, null, 4));
return ports;
}
It's because template variable in your function holds the reference of the template object outside your function.
Try this:
function myFunc (template, count) {
var ports = {};
for(var i = 0; i < count; i++) {
var portNumber = i + 1;
var tmplt = JSON.parse(JSON.stringify(template));
tmplt.portNumber = portNumber;
ports[portNumber + ''] = tmplt;
}
return ports;
}
Related
I'm currently working on trying to create a UDF to split a key value pair string based on web traffic into JSON.
I've managed to get as far as outputting a JSON object but I'd like to be able to dynamically add nested items based on the number of products purchased or viewed based on the index number of the key.
When a product is only viewed, there is always only one product in the string. Only when its a transaction is it more than one but I think it would be good to conform the structure of the json and then identify a purchase or view based on the presence of a transactionid. For example:
Item Purchased:
sessionid=12345&transactionid=555555&product1=apples&productprice1=12&product1qty=1&product2=pears&productprice2=23&product2qty=3&transactionamount=58
The output should look something like this:
[
{
"sessionid":12345,
"transactionid":555555,
"transactionamount":58
},
[
{
"productline":1,
"product":"apples",
"productprice":12,
"productqty":1
},
{
"productline":2,
"product":"pears",
"productprice":23,
"productqty":2
}
]
]
Item Viewed:
sessionid=12345&product1=apples&productprice1=12&product1qty=1&product2=pears&productprice2=23&product2qty=3
[
{
"sessionid":12345,
"transactionid":0,
"transactionamount":0
},
[
{
"productline":1,
"product":"apples",
"productprice":12,
"productqty":1
}
]
]
The result I'll be able to parse from JSON into a conformed table in a SQL table.
What I've tried so far is only parsing the string, but its not ideal to create a table in SQL because the number of purchases can vary:
var string = "sessionid=12345&transactionid=555555&product1=apples&productprice1=12&product1qty=1&product2=pears&productprice2=23&product2qty=3&transactionamount=58";
function splitstring(queryString) {
var dictionary = {};
if (queryString.indexOf('?') === 0) {
queryString = queryString.substr(1);
}
var parts = queryString.split('&');
for (var i = 0; i < parts.length; i++) {
var p = parts[i];
// Step 2: Split Key/Value pair
var keyValuePair = p.split('=');
var key = keyValuePair[0];
var value = keyValuePair[1];
dec_val = decodeURIComponent(value);
final_value = dec_val.replace(/\+/g, ' ');
dictionary[key] = final_value;
}
return (dictionary);
}
console.log(splitstring(string));
Thanks in advance!!!
Feel like this would be less clunky with better param naming conventions, but here's my take...
function parseString(string) {
var string = string || '',
params, param, output, i, l, n, v, k, pk;
params = string.split('&');
output = [{},
[]
];
for (i = 0, l = params.length; i < l; i++) {
param = params[i].split('=');
n = param[0].match(/^product.*?([0-9]+).*/);
v = decodeURIComponent(param[1] || '');
if (n && n[1]) {
k = n[1];
output[1][k] = output[1][k] || {};
output[1][k]['productline'] = k;
pk = n[0].replace(/[0-9]+/, '');
output[1][k][pk] = v;
} else {
output[0][param[0]] = v;
}
}
output[1] = output[1].filter(Boolean);
return output;
}
var string = "sessionid=12345&transactionid=555555&product1=apples&productprice1=12&product1qty=1&product2=pears&productprice2=23&product2qty=3&transactionamount=58";
console.log(parseString(string));
output:
[
{
"sessionid": "12345",
"transactionid": "555555",
"transactionamount": "58"
},
[{
"productline": "1",
"product": "1",
"productprice": "12"
}, {
"productline": "2",
"product": "3",
"productprice": "23"
}]
]
There's probably a far nicer way to do this, but I just wrote code as I thought about it
var string = "sessionid=12345&transactionid=555555&product1=apples&productprice1=12&product1qty=1&product2=pears&productprice2=23&product2qty=3&transactionamount=58";
function splitstring(queryString) {
var dictionary = {};
if (queryString.indexOf('?') === 0) {
queryString = queryString.substr(1);
}
var parts = queryString.split('&');
for (var i = 0; i < parts.length; i++) {
var p = parts[i];
// Step 2: Split Key/Value pair
var keyValuePair = p.split('=');
var key = keyValuePair[0];
var value = keyValuePair[1];
dec_val = decodeURIComponent(value);
final_value = dec_val.replace(/\+/g, ' ');
dictionary[key] = final_value;
}
return (dictionary);
}
function process(obj) {
let i = 1;
const products = [];
while(obj.hasOwnProperty(`product${i}`)) {
products.push({
[`product`]: obj[`product${i}`],
[`productprice`]: obj[`productprice${i}`],
[`productqty`]: obj[`product${i}qty`]
});
delete obj[`product${i}`];
delete obj[`productprice${i}`];
delete obj[`product${i}qty`];
++i;
}
return [obj, products];
}
console.log(process(splitstring(string)));
By the way, if this is in the browser, then splitstring can be "replaced" by
const splitstring = string => Object.fromEntries(new URLSearchParams(string).entries());
var string = "sessionid=12345&transactionid=555555&product1=apples&productprice1=12&product1qty=1&product2=pears&productprice2=23&product2qty=3&transactionamount=58";
function process(string) {
const splitstring = queryString => {
var dictionary = {};
if (queryString.indexOf('?') === 0) {
queryString = queryString.substr(1);
}
var parts = queryString.split('&');
for (var i = 0; i < parts.length; i++) {
var p = parts[i];
// Step 2: Split Key/Value pair
var keyValuePair = p.split('=');
var key = keyValuePair[0];
var value = keyValuePair[1];
dec_val = decodeURIComponent(value);
final_value = dec_val.replace(/\+/g, ' ');
dictionary[key] = final_value;
}
return (dictionary);
};
let i = 1;
const obj = splitstring(string);
const products = [];
while (obj.hasOwnProperty(`product${i}`)) {
products.push({
[`product`]: obj[`product${i}`],
[`productprice`]: obj[`productprice${i}`],
[`productqty`]: obj[`product${i}qty`]
});
delete obj[`product${i}`];
delete obj[`productprice${i}`];
delete obj[`product${i}qty`];
++i;
}
return [obj, products];
}
console.log(process(string));
i'm actually asking myself why the following code is not working properly i found the solution but it's a bit tricky and i don't like this solution
Here is the code and the problem:
function powerSet( list ){
var set = [],
listSize = list.length,
combinationsCount = (1 << listSize),
combination;
for (var i = 1; i < combinationsCount ; i++ ){
var combination = [];
for (var j=0;j<listSize;j++){
if ((i & (1 << j))){
combination.push(list[j]);
}
}
set.push(combination);
}
return set;
}
function getDataChartSpe(map) {
var res = {};
for (var i in map) {
console.log("\n\n");
var dataSpe = {certif: false,
experience: 0,
expert: false,
grade: 1,
last: 100,
name: undefined
};
var compMatchList = [];
for (var j in map[i].comps_match) {
var tmp = map[i].comps_match[j];
compMatchList.push(tmp.name)
}
var tmpList = powerSet(compMatchList);
var lol = [];
lol.push(map[i].comps_match);
for (elem in tmpList) {
console.log("mdr elem === " + elem + " tmplist === " + tmpList);
var tmp = tmpList[elem];
dataSpe.name = tmpList[elem].join(" ");
lol[0].push(dataSpe);
}
console.log(lol);
}
return res;
}
now here is the still the same code but working well :
function powerSet( list ){
var set = [],
listSize = list.length,
combinationsCount = (1 << listSize),
combination;
for (var i = 1; i < combinationsCount ; i++ ){
var combination = [];
for (var j=0;j<listSize;j++){
if ((i & (1 << j))){
combination.push(list[j]);
}
}
set.push(combination);
}
return set;
}
function getDataChartSpe(map) {
var res = {};
var mapBis = JSON.parse(JSON.stringify(map));
for (var i in map) {
var compMatchList = [];
for (var j in map[i].comps_match) {
var tmp = map[i].comps_match[j];
compMatchList.push(tmp.name)
}
var tmpList = powerSet(compMatchList);
mapBis[i].comps_match = [];
for (elem in tmpList) {
tmpList[elem].sort();
mapBis[i].comps_match.push({certif: false,
experience: 0,
expert: false,
grade: 1,
last: 100,
name: tmpList[elem].join(", ")});
}
}
return mapBis;
}
Actually it's a bit disapointig for me because it's exactly the same but the 1st one doesn't work and the second one is working.
so if anyone can help me to understand what i'm doing wrong it'll be with pleasure
ps: i'm sorry if my english is a bit broken
In the first version, you build one dataSpe object and re-use it over and over again. Each time this runs:
lol[0].push(dataSpe);
you're pushing a reference to the same single object onto the array.
The second version of the function works because it builds a new object each time:
mapBis[i].comps_match.push({certif: false,
experience: 0,
expert: false,
grade: 1,
last: 100,
name: tmpList[elem].join(", ")});
That object literal passed to .push() will create a new, distinct object each time that code runs.
I get an object with partial results of match from database.
[Object { home1=4, away1=3, home2=4, away2=5, home3=6, away3=7, home4=6, away4=5, home5=3, away5=6}]
home1 it's a result of first part of home team,
away1 -> away team, home2 it's a result of second part of home team... etc etc
data in my case is each row, which i get from database.
In rows i have td with class: home1, home2, home3, away1, away2 and there are values of corresponding part of match.
I want to check if value is equal to what I got from database.
Something like this
if ($('.home1') === data[index].home1;
if($('.away2') === data[index].away2;
there should be some loop. I have no idea how to do this, I thought about an array
var array = [
{
home1: data[index].home1,
away1: data[index].away1
},
{
home2: data[index].home2,
away2: data[index].away2
},
{
home3: data[index].home3,
away3: data[index].away3
},
{
home4: data[index].home4,
away4: data[index].away4
},
{
home5: data[index].home5,
away5: data[index].away5
}
]
and then for loop:
for(var X=0; X<5;X++){
homeX == data[index].homeX
}
How can I increment name of variable by eval function? or is there any other solution? I'm very confused.
You can access object properties using operator []:
for(var i=0; i<array.length; i++)
{
var item = array[i];
var homePropertyName = 'home' + (i+1);
//now you can access homeX property of item using item[homePropertyName]
//e.g. item[homePropertyName] = data[index][homePropertyName]
}
Maybe you should use a little different structure which might fit your needs better, like this:
array = [
0: array [
"home": "Text for home",
"away": "Text for away"
],
1: array [
"home": "",
"away": ""
]
// More sub-arrays here
];
You can also initialize it with a for loop:
var array = new Array();
var i;
for (i = 0; i < 4; i++) {
array[i] = [
"home": "",
"away": ""
];
}
Or like this:
array[0]["home"] = "Text for home";
array[0]["away"] = "Text for away";
You can use this structure for the data-array also, and then use a for-loop to go through them both (like if you wish to find an element):
var result = NULL;
for (i = 0; i < array.length; i++) {
if ( (array[i]["home"] == data[index]["home"]) &&
(array[i]["away"] == data[index]["away"])
) {
// Found matching home and away
result = array[i];
break;
}
}
if (result != NULL) {
alert("Found match: " + result["home"] + " - " + result["away"]);
}
else {
alert("No match");
}
PS: Code is not tested, let me know if something is wrong.
you can access global properties in browser via window object like this (fiddle):
value1 = "ONE";
alert( window['value'+1] );
But it is not good design. You should look into how to properly format JSON object.
I have something like this:
for(var i=0; i<2; i++)
{
var item = ARR[i];
for(var x=0;x<5;x++){
var hPropertyName = 'home_p' + (x+1);
var aPropertyName = 'away_p' + (x+1);
item[hPropertyName] = ARR[i][hPropertyName];
item[aPropertyName] = ARR[i][aPropertyName];
}
and it works when i create an array:
var ARR = [
{
home_p1: 4,
away_p1: 5,
home_p2: 8,
away_p2: 9,
home_p3: 2,
away_p3: 1,
home_p4: 5,
away_p4: 3,
home_p5: 3,
away_p5: 2
},
{
home_p1: 6,
away_p1: 1,
home_p2: 1,
away_p2: 2,
home_p3: 3,
away_p3: 4,
home_p4: 5,
away_p4: 6,
home_p5: 3,
away_p5: 2
}
];
but I don't have to create an array, because i have to work on object which I get from database :
[Object { event_id=19328, home_result=3, away_result=2, home_p1=4, away_p1=3, home_p2=1, away_p2=2 ...... }]
I'm only interested in these parameters --> home_p , away_p
I want to push it to my array to looks like ARR. I think i should convert an object which I get to an array
If you are using string name for your attributes then you could try using template literals?
var someObject = {}
for(let i=0 ; i<values.length ; i++){
someObject[`home${i+1}`] = values[i];
}
and if you need it to be ES5 you could just use string concatenation. Below is a working example:
values = [1,2,3,4,5];
let someObject = {};
for(let i=0 ; i<values.length ; i++){
someObject[`value${i+1}`]=values[i];
}
console.log(someObject.value1);
console.log(someObject.value2);
console.log(someObject.value3);
console.log(someObject.value4);
console.log(someObject.value5);
window.onload = function () {
x = '';
myArray = [ {a:'a', b:'b'}, {a:'c', b:'d'}, {a:x, b:''} ];
for (i = 0; i < myArray.length; i += 1) {
x = myArray[i].a + myArray[i].b;
}
alert(x); // alerts '';
}
Hi, the above is an example of what I'm trying to do. Basically, I would like for x to be evaluated after the 2nd array element computes it. I think this is called lazy evaluation, but not sure... I'm somewhat new.
How can I process my array in the loop and x be evaluated each time such that when I get to the third iteration, x = 'cd' and will alert as 'cd'?
I think I figured out the answer with your help and the other thread I mentioned in the comment. Just need to wrap x in a function and then define a get function to apply to all elements:
window.onload = function () {
function get(e) {return (typeof e === 'function') ? e () : e; }
var x = '';
myArray = [ {a:'a', b:'b'}, {a:'c', b:'d'}, {a:function() {return x; }, b:''} ];
for (i = 0; i < myArray.length; i += 1) {
x = get(myArray[i].a) + get(myArray[i].b);
}
alert(x); // alerts 'cd';
}
x can be anything then. For example (x + 'xyz') will alert 'cdxyz'. So this way I can have any variable that I want evaluated later (when needed) be evaluated correctly (based on state at that point).
That's what I needed. :)
var elements = [ { a:"a", b:"b"}, {a:"c", b:"d"}, {a:"e", b:"f"} ];
function getter(list, num) {
var i, agg = { a: "", b: "" };
for (i = 0; i <= num; i += 1) {
agg.a += list[i].a;
}
return agg;
}
console.log(getter(elements, 0).a); // "a"
console.log(getter(elements, 1).a); // "ac"
console.log(getter(elements, 2).a); // "ace"
You can use a closure so you can't access the values, like:
var elements = [ { a:"a", b:"b"}, {a:"c", b:"d"}, {a:"e", b:"f"} ];
function make_getter(list) {
return {
get: function (num) {
var i, agg = { a: "", b: "" };
for (i = 0; i <= num; i += 1) {
agg.a += list[i].a;
}
return agg;
}
};
}
var getter = make_getter(elements);
console.log(getter.get(0).a); // "a"
console.log(getter.get(1).a); // "ac"
console.log(getter.get(2).a); // "ace"
You can make different implementations of the aggregation function.
With recursion:
var elements = [ { a:"a", b:"b"}, {a:"c", b:"d"}, {a:"e", b:"f"} ];
function getter(list, num) {
var i, agg = list[num];
if (num > 0) {
agg.a = getter(list, num-1).a + agg.a;
}
return agg;
}
console.log(getter(elements, 0).a); // "a"
console.log(getter(elements, 1).a); // "ac"
console.log(getter(elements, 2).a); // "aace" <-- note, elements are actually modified!
console.log(getter(elements, 2).a); // "aaacaace" <-- note, elements are actually modified!
old answer
Since x is not an object it's value will be copied, rather than passed as a reference.
If you change your code to:
var element = { a: '', b:'' };
myArray = [ {a:'a', b:'b'}, {a:'c', b:'d'}, element ];
for (i = 0; i < myArray.length; i += 1) {
element.a = myArray[i].a + myArray[i].b;
}
alert(el.a); // alerts 'cd';
You will get "cd".
This is not called lazy evaluation by the way. It's just an aggregate or something.
I have an object containing a bunch of similar objects. I would like to get the count of the object only for those where a object property (status) is of a given value (true). For instance, the count of the below object is 3.
{
6:{"name":"Mary", "status":true},
2:{"name":"Mike", "status":true},
1:{"name":"John", "status":false},
4:{"name":"Mark", "status":true},
5:{"name":"Jane", "status":false}
}
Thanks
I recognize you are iterating over an object, not an array, but since the others provide solutions for arrays I recon a solution with array.reduce is in place. Works in most modern browsers (IE9+)
var myArray = [
{"name":"Mary", "status":true},
{"name":"Mike", "status":true},
{"name":"John", "status":false},
{"name":"Mark", "status":true},
{"name":"Jane", "status":false}
];
var result = myArray.reduce(function(previousValue, currentObject){
return previousValue + (currentObject.status ? 1: 0);
}, 0);
Specifically:
var i = 0;
var count = 0;
while (i < array.length) {
if (array[i]['status'] == true) count += 1;
i += 1;
}
More generally, you can use some functional programming:
function count_matches(array, func) {
var i = 0;
var count = 0;
while (i < array.length) {
if (func(array[i])) count += 1;
i += 1;
}
return count;
}
function status_true(obj) {
return obj['status'] == true;
}
count_matches(array, status_true);
The above snippets do the same thing, but the latter is more flexible/potentially neater.
just loop over the array and count how many times the status property is true.
var count = 0;
for (var i = 0; i < yourArray.length; i++){
var current = yourArray[i];
if (current.status) count++
}
LinqJs would work (might be too much for the simple example posted in the question) -
http://linqjs.codeplex.com/
var jsonArray = [
{ "user": { "id": 100, "screen_name": "d_linq" }, "text": "to objects" },
{ "user": { "id": 130, "screen_name": "c_bill" }, "text": "g" },
{ "user": { "id": 155, "screen_name": "b_mskk" }, "text": "kabushiki kaisha" },
{ "user": { "id": 301, "screen_name": "a_xbox" }, "text": "halo reach" }]
// ["b_mskk:kabushiki kaisha", "c_bill:g", "d_linq:to objects"]
var queryResult = Enumerable.From(jsonArray)
.Where(function (x) { return x.user.id < 200 })
.OrderBy(function (x) { return x.user.screen_name })
.Select(function (x) { return x.user.screen_name + ':' + x.text })
.ToArray();
// shortcut! string lambda selector
var queryResult2 = Enumerable.From(jsonArray)
.Where("$.user.id < 200")
.OrderBy("$.user.screen_name")
.Select("$.user.screen_name + ':' + $.text")
.ToArray();
var obj = {
6:{"name":"Mary", "status":true},
2:{"name":"Mike", "status":true},
1:{"name":"John", "status":false},
4:{"name":"Mark", "status":true},
5:{"name":"Jane", "status":false}
};
var count = 0;
for (var prop in obj) {
if(obj[prop].status === true){
count += 1;
}
}
console.log("Output: "+count);
$("#debug").text("Output: "+count);
live demo http://jsbin.com/uwucid/2/edit