Trouble iterating through an object - javascript

I have an object that looks like this:
salesDetails:{ "1":{
"date":"06/22/2014",
"amount":"45",
"currency":"CAD",
"productID":"23",
"status":1},
"2":{
"date":"06/22/2014",
"amount":"120",
"currency":"USD",
"productID":"23",
"status":1},
"3":{
"date":"06/23/2014",
"amount":"100",
"currency":"USD",
"productID":"21",
"status":2},
"4":{
"date":"06/23/2014",
"amount":"250",
"currency":"CAD",
"productID":"25",
"status":1},
"5":{
"date":"06/23/2014",
"amount":"180",
"currency":"USD",
"productID":"24",
"status":1}
}
What i am trying to do is to get all the amount per currency of all that has status of "1" and put it in an object that should look like this:
perCurrency: {
"CAD":{
"0":"45",
"1":"250"},
"USD":{
"0":"120",
"1":"180"}
}
I was able to put all the currency in an object but I'm having trouble with the amount, the last amount from the object overlaps the previous one. I keep on getting {"CAD":{"1":"250"},"USD":{"1":"180"}} Here's my code so far.
function countPerCurrency(){
var currencyArray = new Array();
var perCurrency = {};
var totalSales = Object.size(salesDetails);
for(var i=1; i <= totalSales; i++){
var currency = salesDetails[i]["currency"];
var amount = salesDetails[i]["amount"];
var status = salesDetails[i]["status"];
var totalCurrency = Object.size(currencyAmount[currency]);
var currencyCtr = {};
if(status == 1){
if(!inArray(currency, currencyArray)){
currencyArray.push(currency);
currencyCtr[totalCurrency] = amount;
perCurrency[currency] = currencyCtr;
} else {
var currencyAdd = {};
currencyAdd[totalCurrency] = amount;
perCurrency[currency] = currencyAdd;
}
}
}
}
I know it might seem easy, but I'm lost here.. TIA! :)

The previously accepted answer uses an array of values, whereas you asked for an object. Here's an object version:
var perCurrency = {};
var currencyCount = {};
Object.keys(salesDetails).forEach(function(key) {
var obj = salesDetails[key];
var currency;
if (obj.status == 1) {
currency = obj.currency;
// If this is first for this currency, add it to objects
if (!currencyCount[currency]) {
currencyCount[currency] = 0;
perCurrency[currency] = {};
}
// Add currency values
perCurrency[currency][currencyCount[currency]++] = obj.amount;
}
});
BTW, this has nothing to do with jQuery.
Note that Object.keys is ES5 so may need a polyfill for older browsers, see MDN:Object.keys for code.

try something like this
function countPerCurrency(){
var perCurrency = {};
var totalSales = Object.size(salesDetails);
for(var i=1; i <= totalSales; i++){
var currency = salesDetails[i]["currency"];
var amount = salesDetails[i]["amount"];
var status = salesDetails[i]["status"];
if(status == '1'){
if(perCurrency.hasOwnProperty(currency)){
// if currency already present than get currency array.
var currency_arr = perCurrency[currency];
// add new value to existing currency array.
currency_arr.push(amount);
}else{
// if currency not present than create currency array and add first value;
var currency_arr = [];
currency_arr.push(amount);
// add newly created currency array to perCurrency object
perCurrency[currency] = currency_arr;
}
}
}
console.log(perCurrency);
}
output
perCurrency: {
"CAD":["45","250"],
"USD":["120","180"],
}
I have created currency array instead of key value pair

Change your code like this, i have simplified your things,
function countPerCurrency() {
var perCurrency = {};
var currencyArray = [];
for(i in salesDetails)
{
if(!perCurrency.hasOwnProperty(salesDetails[i].currency) && salesDetails[i].status === "1")
perCurrency[salesDetails[i].currency] = [];
if(salesDetails[i].status === "1")
{
currencyArray = perCurrency[salesDetails[i].currency];
currencyArray.push(salesDetails[i].amount);
perCurrency[salesDetails[i].currency] = currencyArray;
}
}
}

sorry for the late conversation anyway try like this use .each()
var CAD = new Array();
var USD = new Array();
$.each(salesDetails, function (i, value) {
if (value.status == 1) {
if (value.currency == "CAD") {
CAD.push(value.amount);
} else if (value.currency == "USD") {
USD.push(value.amount);
}
}
});
var perCurrency = {
"CAD": CAD,
"USD": USD
}
Demo

Related

JavaScript build nested array from string values

From my data source I am getting values like;
USA |Arizona
USA |Florida
UK |England |Northamptonshire
UK |England |Derbyshire
UK |Wales |Powys
Switzerland|Lucern
These are flat text values that repeat in a column.
I need to build them dynamically into nested array
source: [
{title: "USA", children: [
{title: "Arizona"},
{title: "Florida"}
]}
],
As per https://github.com/mar10/fancytree/wiki/TutorialLoadData
Unfortunately my brain has stopped working today I am can't see a elegant way.
Any pointers would be most gratefully appreciated.
So I solved this eventually using a post from Oskar
function getNestedChildren(arr, parent) {
var out = []
for(var i in arr) {
if(arr[i].parent == parent) {
var children = getNestedChildren(arr, arr[i].id)
if(children.length) {
arr[i].children = children
}
out.push(arr[i])
}
}
return out
}
http://oskarhane.com/create-a-nested-array-recursively-in-javascript/
This builds the nested array.
To ensure inferred values were present (e.g. USA which is in the hierarchy but is not a unique value).
var CountryArray = CountryText.split("|");
// Variables to hold details of each section of the Country path being iterated
var CountryId = '';
var CountryParentPrefix = '';
var CountryParent = '';
// Iterate each section of the delimeted Country path and ensure that it is in the array
for(var i in CountryArray)
{
var CountryId = CountryParentPrefix+CountryArray[i];
// Find the Country id in the array / add if necessary
var result = FlatSource.filter(function (Country) { return Country.id == CountryId });
if (result.length == 0) {
// If the Country is not there then we should add it
var arrCountry = {title:CountryArray[i], parent:CountryParent, id:CountryId};
FlatSource.push(arrCountry);
}
// For the next path of the heirarchy
CountryParent = CountryId;
CountryParentPrefix = CountryId+'|';
}
I did not use Sven's suggestion but I suspect that it is equally valid.
Turn it to JSON:
var str = '"USA|Arizona","USA|Florida","UK|LonelyIsland","UK|England|Northamptonshire","UK|England|Derbyshire","UK|Wales|Powys","UK|England|London|Soho","Switzerland|Lucern';
var jsonStr = "[[" + str.replace(/,/g,'],[') + "\"]]";
jsonStr = jsonStr.replace(/\|/g,'","');
var nested = JSON.parse(jsonStr);
Then play with parents and children.
function findObject(array, key, value) {
for (var i=0; i<array.length; i++) {
if (array[i][key] === value) {
return array[i];
}
}
return null;
}
function obj(arr){
this.title = arr.shift();
}
obj.prototype.addChild = function(arr){
var tmp = new obj(arr);
if(typeof this.children === 'undefined'){
this.children = new Array();
result = this.children[this.children.push(tmp)-1];
}else{
result = findObject(this.children, 'title', tmp.title);
if(!result)
result = this.children[this.children.push(tmp)-1];
}
return result;
}
obj.prototype.addChildren = function(arr){
var obje = this;
while(arr.length>0)
obje = obje.addChild(arr);
}
var finArr = [];
for(i=0; i<nested.length; i++){
var recc = new obj(nested[i]);
if(oldObj = findObject(finArr, 'title', recc.title)){
oldObj.addChildren(nested[i]);
}else{
if(nested[i].length>0)
recc.addChildren(nested[i]);
finArr.push(recc);
}
}
console.log('------------------------------------------')
console.log(JSON.stringify(finArr));
console.log('--------------------The End---------------')

how to reindex object start from 0

I have an object output from below code how to set the index start from 0 in js?
Object
3: Object
id: 34
type: 0
var obj = {};
var edited = false;
for (var i = 0; i < $(".list").length; i++) {
var data_id = parseInt($(".list").eq(i).attr('data-id'));
var data_type = parseInt($(".list").eq(i).attr('data-type'));
if ((data_type != 0)) {
edited = true;
} else {
edited = false;
}
if (edited == true) {
obj[i] = {};
obj[i]['id'] = data_id;
obj[i]['type'] = data_type;
}
}
console.log(obj);
Needs more jQuery ?
var arr = $(".list").filter(function() {
return $(this).data('type') != 0;
}).map(function() {
return { id : $(this).data('id'), type : $(this).data('type') };
}).get();
FIDDLE
Actually if you want to start in 0, use another variable and not "i" (which I think is 3 when you use it as index).
var obj = {};
var edited = false;
var obj_idx = 0;
for (var i = 0; i < $(".list").length; i++) {
var data_id = parseInt($(".list").eq(i).attr('data-id'));
var data_type = parseInt($(".list").eq(i).attr('data-type'));
if ((data_type != 0)) {
edited = true;
} else {
edited = false;
}
if (edited == true) {
obj[obj_idx] = {};
obj[obj_idx]['id'] = data_id;
obj[obj_idx]['type'] = data_type;
obj_idx += 1;
}
}
console.log(obj);
I think this time obj will be something like:
Object
0: Object
id: 34
type: 0
you could fake object as array by Array.prototype.push.call, in that way you could also gain the side effect: obj.length. it's kinda ninja and elegant :]
var obj = {};
var edited = false;
for (var i = 0; i < $(".list").length; i++) {
var data_id = parseInt($(".list").eq(i).attr('data-id'));
var data_type = parseInt($(".list").eq(i).attr('data-type'));
if ((data_type != 0)) {
edited = true;
} else {
edited = false;
}
if (edited == true) {
Array.prototype.push.call(obj, {id: data_id, type: data_type});
}
}
I am going to give a very simple and readable example. Say you've got an object with the following structure:
Object
0: Object
key: 'some-key'
value: 'some-value'
1: Object
...
Then you might want to delete an entry from it and reindex the whole thing, this is how I do it:
// obj is Object from above
const reIndexed = Object.entries(obj).map((element, index) => {
if (parseInt(element[0] != index) {
element[0] = index.toString();
}
return element;
});

Filtering an array of Objects in javascript

I'm really new to JS, and I'm now stuck on a task, hope someone can guide me through it.
I have an Array of Objects, like this one:
var labels = [
// labels for pag 1
{pageID:1, labels: [
{labelID:0, content:[{lang:'eng', text:'Txt1 Eng'}, {lang:'de', text:'Txt1 De:'}]},
{labelID:1, content:[{lang:'eng', text:'Txt 2 Eng:'}, {lang:'de', text:'Txt2 De:'}]},
{labelID:2, content:[{lang:'eng', text:'Txt 3 Eng:'},{lang:'de', text:'Txt 3 De:'}]}
]},
// labels for pag 2
{pageID:2, labels: [
{labelID:0, content:[{lang:'eng', text:'Txt1 Eng'}, {lang:'de', text:'Txt1 De:'}]},
{labelID:1, content:[{lang:'eng', text:'Txt 2 Eng:'}, {lang:'de', text:'Txt2 De:'}]},
{labelID:2, content:[{lang:'eng', text:'Txt 3 Eng:'},{lang:'de', text:'Txt 3 De:'}]}
]}
]
What I am trying to do is write a function to return me an array of labels (Objects) for a specific page and a specific lang. By calling this function specifying pageID 1 and lang eng, I'm basically trying to build an array like this one:
var desideredArray = [
{labelID:0, text:'Txt1 Eng'},
{labelID:1, text:'Txt1 Eng'},
{labelID:2, text:'Txt2 Eng'}
]
Now, I'm trying to write the function to retrieve/build the new array:
this.getLabelsForPageAndLang = function (numPage, lang) {
// this part filters the main object and selects the object with pageID == numPage
var result = labels.filter(function( obj ) {
return obj.pageID == numPage;
});
var tempResult = result[0].labels;
var desiredResults = []; // here I want to store the new objects
for (var i=0; i<tempResult.length; i++) {
var simpleLabelObject = {};
simpleLabelObject.labelID = tempResult[i].labelID;
// simpleLabelObject.text = ?????
results[i] = simpleLabelObject;
}
console.log (results);
};
...but how can I access the right value (the one corresponding the lang selected) in the content property?
You can use the same technique as the one used to keep the matching page: the filter method.
this.getLabelsForPageAndLang = function (numPage, lang) {
// this part filters the main object and selects the object with pageID == numPage
var result = labels.filter(function( obj ) {
return obj.pageID == numPage;
});
var contentFilter = function(obj){ return obj.lang === lang};
var tempResult = result[0].labels;
var desiredResults = []; // here I want to store the new objects
for (var i=0; i<tempResult.length; i++) {
var simpleLabelObject = {};
simpleLabelObject.labelID = tempResult[i].labelID;
var matching = tempResult[i].content.filter(contentFilter);
simpleLabelObject.text = matching[0].text;
desiredResults[i] = simpleLabelObject;
}
console.log (desiredResults);
};
I didn't do bound checks because in your code you assumed there is always a matching element, but it would probably be wise to do it.
And if you want to avoid creating two closures each time the function is called, you can prototype an object for that:
var Filter = function(numPage, lang) {
this.numPage = numPage;
this.lang = lang;
};
Filter.prototype.filterPage = function(obj) {
return obj.pageID === this.numPage;
}
Filter.prototype.filterLang = function(obj) {
return obj.lang === this.lang;
}
Filter.prototype.filterLabels = function(labels) {
var result = labels.filter(this.filterPage, this);
var tempResult = result[0].labels;
var desiredResults = []; // here I want to store the new objects
for (var i=0; i<tempResult.length; i++) {
var simpleLabelObject = {};
simpleLabelObject.labelID = tempResult[i].labelID;
var matching = tempResult[i].content.filter(this.filterLang, this);
simpleLabelObject.text = matching[0].text;
desiredResults[i] = simpleLabelObject;
}
return desiredResults;
}
console.log(new Filter(1, "eng").filterLabels(labels));
Just filter again:
var getLabelsForPageAndLang = function (numPage, lang) {
// this part filters the main object and selects the object with pageID == numPage
var result = labels.filter(function (obj) {
return obj.pageID == numPage;
});
var tempResult = result[0].labels;
var desiredResults = []; // here I want to store the new objects
for (var i = 0; i < tempResult.length; i++) {
var simpleLabelObject = {};
simpleLabelObject.labelID = tempResult[i].labelID;
var lg = tempResult[i].content.filter(function (lg) {
return lg.lang == lang;
});
simpleLabelObject.text = lg[0].text;
desiredResults.push(simpleLabelObject);
}
console.log(desiredResults);
};
http://jsfiddle.net/9q5zF/
A rather 'safe' implementation for cases when pages have the same pageID and multiple contents with the same lang:
this.getLabelsForPageAndLang = function(numPage, lang) {
var result = [];
var pages = labels.filter(function( obj ) {
return obj.pageID === numPage;
});
for (var p = pages.length - 1; p >= 0; p--) {
var page = pages[p];
for(var i = page.labels.length - 1; i >= 0; i--) {
var labelId = page.labels[i].labelID;
for (var j = page.labels[i].content.length - 1; j >= 0; j--){
if (page.labels[i].content[j].lang === lang) {
result.push({labelID: labelId, test: page.labels[i].content[j].text});
}
}
}
}
console.log(result);
}
Fiddle: http://jsfiddle.net/6VQUm/

change array to json

I've been playing around with javascript and casperjs. I have the following lines of code.
casper.thenOpen('somesite', function() {
console.log('clicked ok, new location is ' + this.getCurrentUrl());
// Get info on all elements matching this CSS selector
var town_selector = 'div tr';
var town_names_info = this.getElementsInfo(town_selector); // an array of object literals
// Pull out the town name text and push into the town_names array
var town_names = [];
for (var i = 0; i < town_names_info.length; i++) {
town_names.push(town_names_info[i].text.trim());}
// Dump the town_names array to screen
utils.dump(town_names);
casper.capture('capture5.png');
});
my output is this.
[
"Address:\n \n address",
"City:\n \ncity",
"State:\n \nstate",
"Zip:\n \nzip",
]
how can I make it json? like this.
{
"Address":"address",
"City":"city",
"State":"state",
"Zip":"zip"
}
Thanks in advance.
You can use something like this:
function arrayToObject(arr) {
var out = {};
arr.forEach(function (element) {
var keyvalue = element.replace(/[\n\s]+/, '').split(':');
var key = keyvalue[0];
var value = keyvalue[1];
out[key] = value;
});
return out;
}
then you can do:
var json = JSON.stringify(arrayToObject(myArray));
Update:
> How can I change this to split only the first occurrence of colon?
Use this:
arr.forEach(function (element) {
var keyvalue = element.replace(/[\n\s]+/, '');
var key = keyvalue.substring(0, element.indexOf(':'));
var value = keyvalue.substring(key.length + 1);
out[key] = value;
});

Dynamically building array, appending values

i have a bunch of options in this select, each with values like:
context|cow
context|test
thing|1
thing|5
thing|27
context|beans
while looping through the options, I want to build an array that checks to see if keys exist, and if they don't they make the key then append the value. then the next loop through, if the key exists, add the next value, comma separated.
the ideal output would be:
arr['context'] = 'cow,test,beans';
arr['thing'] = '1,5,27';
here's what i have so far, but this isn't a good strategy to build the values..
function sift(select) {
vals = [];
$.each(select.options, function() {
var valArr = this.value.split('|');
var key = valArr[0];
var val = valArr[1];
if (typeof vals[key] === 'undefined') {
vals[key] = [];
}
vals[key].push(val);
});
console.log(vals);
}
Existing code works by changing
vals=[];
To
vals={};
http://jsfiddle.net/BrxuM/
function sift(select) {
var vals = {};//notice I made an object, not an array, this is to create an associative array
$.each(select.options, function() {
var valArr = this.value.split('|');
if (typeof vals[valArr[0]] === 'undefined') {
vals[valArr[0]] = '';
} else {
vals[valArr[0]] += ',';
}
vals[valArr[0]] += valArr[1];
});
}
Here is a demo: http://jsfiddle.net/jasper/xtfm2/1/
How about an extensible, reusable, encapsulated solution:
function MyOptions()
{
var _optionNames = [];
var _optionValues = [];
function _add(name, value)
{
var nameIndex = _optionNames.indexOf(name);
if (nameIndex < 0)
{
_optionNames.push(name);
var newValues = [];
newValues.push(value);
_optionValues.push(newValues);
}
else
{
var values = _optionValues[nameIndex];
values.push(value);
_optionValues[nameIndex] = values;
}
};
function _values(name)
{
var nameIndex = _optionNames.indexOf(name);
if (nameIndex < 0)
{
return [];
}
else
{
return _optionValues[nameIndex];
}
};
var public =
{
add: _add,
values: _values
};
return public;
}
usage:
var myOptions = MyOptions();
myOptions.add("context", "cow");
myOptions.add("context","test");
myOptions.add("thing","1");
myOptions.add("thing","5");
myOptions.add("thing","27");
myOptions.add("context","beans");
console.log(myOptions.values("context").join(","));
console.log(myOptions.values("thing").join(","));
working example: http://jsfiddle.net/Zjamy/
I guess this works, but if someone could optimize it, I'd love to see.
function updateSiftUrl(select) { var
vals = {};
$.each(select.options, function() {
var valArr = this.value.split('|');
var key = valArr[0];
var val = valArr[1];
if (typeof vals[key] === 'undefined') {
vals[key] = val;
return;
}
vals[key] = vals[key] +','+ val;
});
console.log(vals);
}
Would something like this work for you?
$("select#yourselect").change(function(){
var optionArray =
$(":selected", $(this)).map(function(){
return $(this).val();
}).get().join(", ");
});
If you've selected 3 options, optionArray should contain something like option1, option2, option3.
Well, you don't want vals[key] to be an array - you want it to be a string. so try doing
if (typeof vals[key] === 'undefined') {
vals[key] = ';
}
vals[key] = vals[key] + ',' + val;

Categories

Resources