Related
I have a array list which is bellow and want to assign a value from bottom to up.
Code sample:
var tempArrayList=[
{org1:null,org2:"Office",org3:"HR",org4:"Payroll",org5:"Pay"},
{org1:null,org2:null,org3:"HR",org4:"Payroll",org5:"Pay"},
{org1:null,org2:"Office",org3:null,org4:null,org5:"Pay"},
{org1:null,org2:"Office",org3:"HR",org4:"Payroll",org5:"Pay"},
{org1:"head1",org2:null,org3:null,org4:"Payroll",org5:"Pay"}
];
for(var i=0;i<tempArrayList.length;i++) {
var temp=tempArrayList[i];
var org1=temp.org1;
var org2=temp.org2;
var org3=temp.org3;
var org4=temp.org4;
var org5=temp.org5;
document.write(JSON.stringify(temp));
document.writeln("<br>");
}
My Questions: how can I set the org2 value to org1, org3 value to org2......
// if org1 is null then temp.org1 = temp.org2, temp.org2 = temp.org3, temp.org3 = temp.org4, temp.org4 = temp.org5
// if org1 and org2 is null then temp.org1 = temp.org3, temp.org2 = temp.org4, temp.org3 = temp.org5, temp.org4 = null
Filter all the null out of values array then loop over keys and assign filtered value or null
var tempArrayList=[
{org1:null,org2:"Office",org3:"HR",org4:"Payroll",org5:"Pay"},
{org1:null,org2:null,org3:"HR",org4:"Payroll",org5:"Pay"},
{org1:null,org2:"Office",org3:null,org4:null,org5:"Pay"},
{org1:null,org2:"Office",org3:"HR",org4:"Payroll",org5:"Pay"},
{org1:"head1",org2:null,org3:null,org4:"Payroll",org5:"Pay"}
];
tempArrayList.forEach((o) => {
const vals = Object.values(o).filter(v => v);
Object.keys(o).forEach((key, i) => o[key] = vals[i] || null);
});
console.log(tempArrayList)
.as-console-wrapper {max-height:100%!important;}
Accepted answer fails on falsy values ({org1:false}), mutates original object and falsely assumes Object.keys returns in a particular order.
There is no guarantee in the order Object.keys returns the array of keys in the right order:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/keys
in the same order as that provided by a for...in loop
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...in
A for...in loop iterates over the properties of an object in an arbitrary order
If the code with Object.keys works then try it again but add this first:
tempArrayList = tempArrayList.map(
x =>
Object.keys(x).reverse().reduce(
(acc,key) => {acc[key]=x[key];return acc;}
,{}
)
);
Here is one solution to the problem that doesn't rely on Object.keys order, does not mutate and does not fail on falsy member values:
const collapse = function(direction,reason,subject,seed,keys){
if(Array.isArray(subject)){
keys = (function(x){
const ret = [];
while(++x<subject.length){
ret.push(x);
}
return ret;
}(-1));
}
keys =
(direction>0)
? keys
: keys.reverse();
const sortedKeys = keys.filter(
function(key){return !reason(subject[key])}
).concat(
keys.filter(
function(key){return reason(subject[key])}
)
);
return keys.reduce(
function(acc,key,index) {
acc[key] = subject[sortedKeys[index]]
return acc;
}
,seed
);
}
const collapseLeft = function(reason,keys){
return function(seed,subject){
return collapse(1,reason,subject,seed,keys);
}
};
const collapseRight = function(reason,keys){
return function(seed,subject){
return collapse(-1,reason,subject,seed,keys);
}
};
const tempArrayList=[
{org1:null,org2:"Office",org3:"HR",org4:"Payroll",org5:"Pay"},
{org1:null,org2:null,org3:"HR",org4:"Payroll",org5:"Pay"},
{org1:null,org2:"Office",org3:null,org4:null,org5:"Pay"},
{org1:null,org2:"Office",org3:"HR",org4:"Payroll",org5:"Pay"},
{org1:"head1",org2:null,org3:"Pay",org4:null,org5:null}
];
const isNull = function(x){return x===null;};
console.log(
tempArrayList.map(
function(item){
//seed can be an object ({}) or array ([]) see other log
return collapseLeft(
isNull,
["org1", "org2", "org3", "org4", "org5"]
)
({},item);
}
)
);
//collapse right example
console.log(
JSON.stringify(
collapseRight(
isNull,
["org1", "org2", "org3", "org4", "org5"]
)({},{org1:"head1",org2:null,org3:"Pay",org4:null,org5:null})
,undefined
,2
)
);
//array example (seed is [])
console.log(
JSON.stringify(
collapseRight(isNull)([],[1,2,3,null,4,null,5])
,undefined
,2
)
);
Is this what you're looking for?
This code loops through the object keys, moving the values up and setting the last one to null.
var tempArrayList=[
{org1:null,org2:"Office",org3:"HR",org4:"Payroll",org5:"Pay"},
{org1:null,org2:null,org3:"HR",org4:"Payroll",org5:"Pay"},
{org1:null,org2:"Office",org3:null,org4:null,org5:"Pay"},
{org1:null,org2:"Office",org3:"HR",org4:"Payroll",org5:"Pay"},
{org1:"head1",org2:null,org3:null,org4:"Payroll",org5:"Pay"}
];
for (var i = 0; i < tempArrayList.length; i++) {
var keys = Object.keys (tempArrayList[i]);
for (var j = 0; j < keys.length; j++) {
if (j < keys.length - 1) {
tempArrayList[i][keys[j]] = tempArrayList[i][keys[j + 1]];
} else {
tempArrayList[i][keys[j]] = null;
}
}
}
I am receiving data in object form. that object contains properties in which three keys are holding array values. I want to push concat those three array into one master Array. But should be in preferred sequence. Like
var obj = {'type':['a','b'],'power':[500,700],'make':['2012','2015']}
oneArray(obj,'make','type','power')
The master Array should have first 'make', 'type' and then 'power' keys Array from object. Right now it is coming in order which is given in obj
Fidde
var obj = {'type':['a','b'],'power':[500,700],'make':['2012','2015']}
var oneArray = function (obj,first,second,third){
var newObj = obj;
var list = [];
for(var key in newObj){
if (newObj[key] instanceof Array) {
if (!list) {
list = newObj[key];
}
else {
list = list.concat(newObj[key]);
}
}
}
newObj['all'] = list;
return newObj
}
console.log(oneArray(obj,'make','type','power'))
I'm not sure I have understood your question, but try this...
This onArray() function takes parameters that indicating priorities in orderly manner but first parameter.
var obj = {'type':['a','b'],'power':[500,700],'make':['2012','2015']}
var oneArray = function(obj) {
var newObj = obj;
var list = [];
var priorityList = arguments;
for( var i = 1 ; i < priorityList.length ; i++ ) {
if( newObj[ priorityList[i] ] instanceof Array ) {
for( var key in newObj[ priorityList[i] ] ) {
list.push( newObj[ priorityList[i] ][ key ] );
}
}
}
newObj['all'] = list;
return newObj;
}
console.log(oneArray(obj,'make','type','power'));
I have an array of objects.All these objects do not necessarily have the properties in common.
In case some of the objects from an array do have common property, I need to find their sum.
[{"taxAmount":572.26,"totalAmount":2004,"totalDiscount":0,"totalItems":12,"gTotal":2576.2599999999998,"count":4,"deployment":{"_id":"554c92f979d26026307a5a9b","name":"Punjabi Bagh"}},
{"taxAmount":304.9,"totalAmount":1111,"totalDiscount":0,"totalItems":9,"gTotal":1415.8999999999999,"count":2,"deployment{"_id":"554c930579d26026307a5a9c","name":"Pitampura"}},
{"deployment":{"_id":"554c930c79d26026307a5a9d","name":"Model Town"}},
{"deployment":{"_id":"554c945079d26026307a5cae","name":"Dwarka"}},
{"deployment":{"_id":"554cd66c0a40ccd2416e38e7","name":"Green Park"}}]
In above example, I need to add calculate individual sums of TaxAmount and totalAmount.
Also, I would need number of objects that have let's say totalAmount property.
How can I go about this in javascript?
also, is there a quick way to check if an object has any extra property except for what we have been iterating so far?
You are on the right path - reduce is one way to do it (you'll also need Object.keys to loop through each object's properties
Comments inline - note that this does a (simple) isNumber check before counting / adding
var data = [{"taxAmount":572.26,"totalAmount":2004,"totalDiscount":0,"totalItems":12,"gTotal":2576.2599999999998,"count":4,"deployment":{"_id":"554c92f979d26026307a5a9b","name":"Punjabi Bagh"}},
{"taxAmount":304.9,"totalAmount":1111,"totalDiscount":0,"totalItems":9,"gTotal":1415.8999999999999,"count":2,"deployment":{_id:"554c930579d26026307a5a9c","name":"Pitampura"}},
{"deployment":{"_id":"554c930c79d26026307a5a9d","name":"Model Town"}},
{"deployment":{"_id":"554c945079d26026307a5cae","name":"Dwarka"}},
{ "deployment": { "_id": "554cd66c0a40ccd2416e38e7", "name": "Green Park" } }]
var result = data.reduce(function (a, b) {
// loop through the properties
Object.keys(b).forEach(function (key) {
// check if it's a number
if (!isNaN(parseFloat(b[key]))) {
// get the running count / sum for this key or initialize a new one
a[key] = a[key] || { sum: 0, count: 0 }
a[key].sum += Number(b[key]);
a[key].count++;
}
})
return a;
}, {})
console.log(result)
var obj = [{"taxAmount":572.26,"totalAmount":2004,"totalDiscount":0,"totalItems":12,"gTotal":2576.2599999999998,"count":4,"deployment":{"_id":"554c92f979d26026307a5a9b","name":"Punjabi Bagh"}},
{"taxAmount":304.9,"totalAmount":1111,"totalDiscount":0,"totalItems":9,"gTotal":1415.8999999999999,"count":2,"deployment":{"_id":"554c930579d26026307a5a9c","name":"Pitampura"}},
{"deployment":{"_id":"554c930c79d26026307a5a9d","name":"Model Town"}},
{"deployment":{"_id":"554c945079d26026307a5cae","name":"Dwarka"}},
{"deployment":{"_id":"554cd66c0a40ccd2416e38e7","name":"Green Park"}}],
sumObj = { "taxAmount":0, "totalAmount":0 };
for( var o in obj ){
sumObj.taxAmount += obj[ o ].taxAmount || 0;
sumObj.totalAmount += obj[ o ].totalAmount || 0;
}
This obj[ o ].taxAmount || 0 tests if obj[ o ] has property taxAmount and if it's true-like. If it does, return it, else return 0.
Assuming your data is contained in an array called values:
var taxAmount = 0,
totalAmount = 0,
objectsWithTotalAmount = 0;
for (int i = 0; i < values.length; i++) {
if (values[i].hasOwnProperty("taxAmount") {
taxAmount += values[i].taxAmount;
}
if (values[i].hasOwnProperty("totalAmount") {
totalAmount += values[i].totalAmount;
objectsWithTotalAmount++;
}
}
With .hasOwnProperty() you check whether the object contains that property. That way you have your sums at taxAmount and totalAmount, as well as the number of objects that have the totalAmount property.
Pass in prop name to function, check every property of each array instance
var testArr = [{"taxAmount":572.26,"totalAmount":2004,"totalDiscount":0,"totalItems":12,"gTotal":2576.2599999999998,"count":4,"deployment":{"_id":"554c92f979d26026307a5a9b","name":"Punjabi Bagh"}},
{"taxAmount":304.9,"totalAmount":1111,"totalDiscount":0,"totalItems":9,"gTotal":1415.8999999999999,"count":2,"deployment":{"_id":"554c930579d26026307a5a9c","name":"Pitampura"}},
{"deployment":{"_id":"554c930c79d26026307a5a9d","name":"Model Town"}},
{"deployment":{"_id":"554c945079d26026307a5cae","name":"Dwarka"}},
{"deployment":{"_id":"554cd66c0a40ccd2416e38e7","name":"Green Park"}}];
var testTotal = getTotal('taxAmount');
alert(testTotal);
function getTotal(propName) {
var total = 0;
for (var i = 0; i < testArr.length; i++) {
for (var key in testArr[i]) {
if (testArr[i].hasOwnProperty(key)) {
if (key === propName) {
total = total + testArr[i][key];
}
}
}
}
return total;
}
Not sure what you realy want. Is it this ?
var obj = [{"taxAmount":572.26,"totalAmount":2004,"totalDiscount":0,"totalItems":12,"gTotal":2576.2599999999998,"count":4,"deployment":{"_id":"554c92f979d26026307a5a9b","name":"Punjabi Bagh"}},
{"taxAmount":304.9,"totalAmount":1111,"totalDiscount":0,"totalItems":9,"gTotal":1415.8999999999999,"count":2,"deployment":{"_id":"554c930579d26026307a5a9c","name":"Pitampura"}},
{"deployment":{"_id":"554c930c79d26026307a5a9d","name":"Model Town"}},
{"deployment":{"_id":"554c945079d26026307a5cae","name":"Dwarka"}},
{"deployment":{"_id":"554cd66c0a40ccd2416e38e7","name":"Green Park"}}],
sumObj = { "taxAmount":[], "totalAmount":[] };
for( var o in obj ){
var current = obj[ o ];
current.taxAmount && sumObj.taxAmount.push( current.taxAmount );
current.totalAmount && sumObj.totalAmount.push( current.totalAmount );
}
I'd use a recursive function, they're really easy to use in Javascript, just keep passing the same variable:
function getSumAllProps(){
var objSums = {};
var arrObjs = [{"taxAmount":572.26,"totalAmount":2004,"totalDiscount":0,"totalItems":12,"gTotal":2576.2599999999998,"count":4,"deployment":{"_id":"554c92f979d26026307a5a9b","name":"Punjabi Bagh"}},{"taxAmount":304.9,"totalAmount":1111,"totalDiscount":0,"totalItems":9,"gTotal":1415.8999999999999,"count":2,"deployment":{"_id":"554c930579d26026307a5a9c","name":"Pitampura"}},{"deployment":{"_id":"554c930c79d26026307a5a9d","name":"Model Town"}},{"deployment":{"_id":"554c945079d26026307a5cae","name":"Dwarka"}},{"deployment":{"_id":"554cd66c0a40ccd2416e38e7","name":"Green Park"}}];
for( var prop in arrObjs ){
sumProps( arrObjs[i], objSums );
}
console.log( objSums );
}
function sumProps( objIn, newObjSum ){
for( var theProp in objIn ){
if( typeof objIn[ theProp ] === 'object'){
sumProps( objIn[ theProp ], newObjSum );
}else{
if( !newObjSum[ theProp ] ) newObjSum[ theProp ] = 0;
newObjSum[ theProp ] += objIn[ theProp ];
}
}
}
You should use the Array.prototype.reduce() method. Moreover, you can do it by using the functional way and high order function.
Moreover, you can use the Arguments object in order to pass multiple parameters.
I've made a generic function in order to reduce your data.
var data = [{"taxAmount":572.26,"totalAmount":2004,"totalDiscount":0,"totalItems":12,"gTotal":2576.2599999999998,"count":4,"deployment":{"_id":"554c92f979d26026307a5a9b","name":"Punjabi Bagh"}},
{"taxAmount":304.9,"totalAmount":1111,"totalDiscount":0,"totalItems":9,"gTotal":1415.8999999999999,"count":2,"deployment":{"_id":"554c930579d26026307a5a9c","name":"Pitampura"}},
{"deployment":{"_id":"554c930c79d26026307a5a9d","name":"Model Town"}},
{"deployment":{"_id":"554c945079d26026307a5cae","name":"Dwarka"}},
{"deployment":{"_id":"554cd66c0a40ccd2416e38e7","name":"Green Park"}}];
function reducer(data, func){
//Retrieve our arguments parameter
var args = [].slice.call(arguments);
//Remove first and second element from array args
args.splice(0,2);
//Start reducing our data, initialize with an empty object
return data.reduce(function(result, current){
//ForEach key
args.forEach(function(key){
//If our object get current key, add curent value, instead of initialize it with 0
//Apply our high order function
func(result, current, key);
});
//Return our current object result
return result;
}, {});
}
//Function to sum some properties
function sum(result, current, key){
return result[key] = (result[key] || 0) + (current[key] || 0);
}
//Function to count occurence of properties
function number(result, current, key){
return current.hasOwnProperty(key)
? (result[key] = (++result[key] || 1), result)
: result
}
var res1 = reducer(data, sum, 'taxAmount', 'totalAmount');
var res2 = reducer(data, number, 'taxAmount');
So you will be able with one function to sum specific field, or count occurence, just by specifying an high order function.
I need to save order in array. A normal array was destroying it, so i found associative array, but with indexes from regexp was sorting records too.
My function is
var myArray = {};
var searchIndex = '';
$("#searchList").find('li').each(function( index ) {
id = $( this ).attr('id');
if(id.match(/search(:?\d+|\w+)/)){
searchIndex = id.match(/search(\d+|\w+)/)[1];
myArray[searchIndex] = "empty";
}
});
This code works well, order are saved.
myArray[id] = "empty";
http://screenshooter.net/100008827/fhbsvjm
But when i want to remove string "search" from id, by regexp, array just sorting indexes...
searchIndex = id.match(/search(\d+|\w+)/)[1];
myArray[searchIndex] = "empty";
http://screenshooter.net/100008827/gmxusyu
But order should be last->7->9->8
JavaScript does not have associative arrays. The plain objects in JavaScript are similar to associative arrays in some ways, but the order of their properties is not guaranteed.
If you want an associative array that preserves the order of items in the order they were added, it is possible to create one from scratch. Here is a fairly simple implementation that provides that functionality:
function AssociativeArray() {
var items = [];
var refs = {};
this.set = function(key, value) {
if (key in refs) {
refs[key].value = value;
} else {
var entry = { key: key, value: value };
items.push(entry);
refs[key] = entry;
}
};
this.get = function(key) {
var entry = refs[key];
return entry && entry.value;
};
this.allItems = function() {
return items.slice();
};
}
var assoc = new AssociativeArray();
assoc.set(7, "hello");
assoc.set(3, "goodbye");
assoc.set("cheer", "yay");
var items = assoc.allItems();
for (var i = 0; i < items.length; i += 1) {
console.log(items[i].key + " - " + items[i].value);
}
console.log("The item with key 7 is: " + assoc.get(7));
The way you would adapt this to your current code is:
var myArray = new AssociativeArray();
$("#searchList").find('li').each(function( index ) {
var id = $( this ).attr('id'),
searchIndex;
if(id.match(/search(:?\d+|\w+)/)){
searchIndex = id.match(/search(\d+|\w+)/)[1];
myArray.set(searchIndex, "empty");
}
});
The first code snippet above shows how to iterate through the array in the order that items were added.
var Array = [{"Name":"Temp","Date":"2014-10-23"},
{"Name":"Temp","Date":"2014-10-22"},
{"Name":"Temp","Date":"2014-10-18"},
{"Name":"Temp","Date":"2014-10-19"},
{"Name":"Temp2","Date":"2014-10-12"},
{"Name":"Temp2","Date":"2014-06-12"}]
What would be the best way to filter the above array on the following condition.
*If the name is the same, then filter away all the objects with the same name and leave only the object with the latest date left.
All I can think of is to do for loops. Note that Date is a real dateObject and not a string as I have wrote above which means that you can do Date comparisons.
Using Array.reduce(), i was able to get it down to an object containing only Temp and Temp2 with their dates:
var obj = array.reduce(function(base,cur){
if (base[cur.Name]) {
if (base[cur.Name].Date < cur.Date) {
base[cur.Name].Date = cur.Date;
} else {
return base;
}
} else {
base[cur.Name] = cur;
return base;
}
},{});
From there, you can just get the object's values with Object.keys().map():
array = Object.keys(obj).map(function(k){
return obj[k];
});
var array = [{"Name":"Temp","Date":new Date("2014-10-23")},
{"Name":"Temp","Date":new Date("2014-10-22")},
{"Name":"Temp","Date":new Date("2014-10-18")},
{"Name":"Temp","Date":new Date("2014-10-19")},
{"Name":"Temp2","Date":new Date("2014-10-12")},
{"Name":"Temp2","Date":new Date("2014-06-12")}];
var obj = {};
for(var i in array){
if(!obj[array[i].Name] || obj[array[i].Name].getTime() < array[i].Date.getTime())
obj[array[i].Name] = array[i].Date;
}
then if you need it to be an array of objects:
array = [];
for(var name in obj){
array.push({Name: name, Date: obj[name]});
}
var Array = [{"Name":"Temp","Date":"2014-10-23"},
{"Name":"Temp","Date":"2014-10-22"},
{"Name":"Temp","Date":"2014-10-18"},
{"Name":"Temp","Date":"2014-10-19"},
{"Name":"Temp2","Date":"2014-10-12"},
{"Name":"Temp2","Date":"2014-06-12"}]
var result = {};
Array.forEach(function(item) {
var name = item['Name'];
if(result[name]) {
result[name].push(item['Date']);
} else {
result[name] = [item['Date']];
}
})
Object.keys(result).forEach(function(item) {
result[item] = Math.max.apply(null, result[item]);
})
aggragate the array by name to {Name: 'Temp', Date: ['2014-10-23', '2013-10-32', 'xxxx']}
then get the max date by Math.max.apply
Here you go, Works perfect for any random orders
var Array = [{"Name":"Temp","Date":"2014-10-03"},
{"Name":"Temp","Date":"2014-10-22"},
{"Name":"Temp","Date":"2014-10-18"},
{"Name":"Temp","Date":"2014-10-19"},
{"Name":"Temp2","Date":"2014-10-12"},
{"Name":"Temp2","Date":"2014-06-12"}];
var tempArray = []; //This array will hold your Result Set
var tempArrayName = [];
var tempDate = {};
$.each(Array, function(i, v) {
if(tempArrayName.indexOf(Array[i].Name) < 0){
tempArray.push({ "Name":Array[i].Name,"Date":Array[i].Date});
tempArrayName.push(Array[i].Name);
tempDate[Array[i].Name] = Array[i].Date;
}else{
if( new Date((Array[i].Date))> new Date(tempDate[Array[i].Name])){
$.each(tempArray, function(j, k) {
if(tempArray[j].Name == Array[i].Name){
tempArray[j].Date = Array[i].Date;
}
});
}
}
});
console.log(tempArray);
I'd advise against overwriting the Array object. Anyhow,
one way would be to group the dates using an object:
var data = [
{"Name":"Temp","Date": new Date("2014-10-23")},
{"Name":"Temp","Date": new Date("2014-10-22")},
{"Name":"Temp","Date": new Date("2014-10-18")},
{"Name":"Temp","Date": new Date("2014-10-19")},
{"Name":"Temp2","Date": new Date("2014-10-12")},
{"Name":"Temp2","Date": new Date("2014-06-12")}
];
var name2dates = Object.create(null);
data.forEach(function(thing){
if(!name2dates[thing.Name]){
name2dates[thing.Name] = thing.Date;
}else{
name2dates[thing.Name] = thing.Date > name2dates[thing.Name] ?
thing.Date : name2dates[thing.Name];
}
});
And to create a 'filtered' array from this, if that's what you
need, then:
Object.keys(name2dates).map(function(name){
return {Name: name, Date: name2dates[name]};
});
Is this helpful?
$.grep(Array, function(v) {
return v.Name === "Temp";
}).reduce(function (a, b) { return a.Date > b.Date ? a : b; });