How to solve this without using three nested for loops - javascript

I have an array of objects something like this
var data = [{"2017-09-13":{date_time:"2017-09-13",value:"20"}},{"2017-09-13":{date_time:"2017-09-13",value:"22"}},{"2017-09-15":{date_time:"2017-09-15",value:"25"}},{"2017-09-15":{date_time:"2017-09-15",value:"30"}},{"2017-09-16":{date_time:"2017-09-16",value:"10"}}];
I have an array of dates like this
var dates = ["2017-09-13","2017-09-15"];
I want to modify the data array in such a way that it only contains the days mentioned in the dates array. I have tried something like this
var date = [];
for (var i = 0; i < data.length; i++) {
for (var j = 0; j < dates.length; j++) {
for (key in data[i]) {
if (dates[j] == key) {
date.push(data[i])
}
}
}
}
And it gives me the required result. However this is not efficient and is lagging the application. Is there any efficient way to go about it?
EDIT: Updated the correct data structure

const data = [
{
"2017-09-13": {
"date_time": "2017-09-13",
"value": "20"
}
},
{
"2017-09-13": {
"date_time": "2017-09-13",
"value": "22"
}
},
{
"2017-09-15": {
"date_time": "2017-09-15",
"value": "25"
}
},
{
"2017-09-15": {
"date_time": "2017-09-15",
"value": "30"
}
},
{
"2017-09-16": {
"date_time": "2017-09-16",
"value": "10"
}
}
];
const dates = ["2017-09-13", "2017-09-15"];
const datesSet = new Set(dates);
const filteredData = data.filter(item => datesSet.has(Object.keys(item)[0]));
console.log(filteredData);
Consider removing the use of dates as keys, as they seem to be redundant information:
const data = [
{
"date_time": "2017-09-13",
"value": "20"
},
{
"date_time": "2017-09-13",
"value": "22"
},
{
"date_time": "2017-09-15",
"value": "25"
},
{
"date_time": "2017-09-15",
"value": "30"
},
{
"date_time": "2017-09-16",
"value": "10"
}
];
const dates = ["2017-09-13", "2017-09-15"];
const datesSet = new Set(dates);
const filteredData = data.filter(item => datesSet.has(item.date_time));
console.log(filteredData);

Your datastructure is ugly. You will always need two loops to iterate it. However, we could set up a more elegant datastructure ( aka a Map), which we can access more easily:
const days = new Map();
for(const obj of data){
for(day in obj){
if( days.has(day) ){
days.get(day).push( obj[day] );
} else {
days.set(day, [ obj[day] ]);
}
}
}
After the Map is created, you can simply do:
days.get("2017-09-13")
to get an array of objects with datetime/values. That can be iterated easily:
days.get("2017-09-13").forEach( ({value}) => {
console.log(value);
});
Or getting multiple dates:
const result = new Map(
dates.map(date => [date, days.get( date )] )
);
console.log( [...result] );
and data only:
const result = [];
dates.forEach(date => result.push(...days.get(date)));

Here is a solution with only two for loops.
var data = [{'2017-09-13':{date_time:"2017-09-13",value:"20"}},{'2017-09-13':{date_time:"2017-09-13",value:"22"}},{'2017-09-15':{date_time:"2017-09-15",value:"25"}},{'2017-09-15':{date_time:"2017-09-15",value:"30"}},{'2017-09-16':{date_time:"2017-09-16",value:"10"}}];
var date = [];
for (var i = 0; i < data.length; i++) {
for (key in data[i]) {
if (date.indexOf(key) === -1) {
date.push(key);
}
}
}
console.log(date);

var dataByDate = { };
for (var i = 0; i < data.length; i++) {
for (var j in data[i])
dataByDate[j] = dataByDate[j] || true;
}
Converts the data to
{ '2017-09-13': true, '2017-09-15': true, '2017-09-16': true }
Then you can do
for (var i in dataByDate) { ... }

Related

parse array of object that contains JSON elements

First let me break down the data:
I have an array that contains 3 elements...
Each Element is an object with name and arrayOfJSON as keys...
Inside arrayOfJSON there could be any number of JSON strings as elements...
I need to capture the position where Alex#gmail occurs for both the array mess and arrayOfJSON
Result Should Be:
position_of_mess = [0,2]
position_of_arrayOfJSON_for_position_of_mess_0 = [0]
position_of_arrayOfJSON_for_position_of_mess_2 = [1]
What I'm trying at the moment:
For loop through mess, for loop through arrayOfJSON , and JSON.parse() for Alex#gmail.
going to take me a few mins to update.
If y'all think it can be done without a for-loop let me know.
Update: almost there
mess = [{
"name": "user1",
"arrayOfJSON": `[{"email":"Alex#gmail","hobby":"coding"},{"email":"bob#gmail","hobby":"coocking"}]`
},
{
"name": "user2",
"arrayOfJSON": `[{"email":"Chris#gmail","hobby":"coding"},{"email":"bob#gmail","hobby":"coocking"}]`
},
{
"name": "user3",
"arrayOfJSON": `[{"email":"bob#gmail","hobby":"coocking"},{"email":"Alex#gmail","hobby":"coding"}]`
}
]
console.log(mess)
for (i = 0; i < mess.length; i++) {
console.log(JSON.parse(mess[i].arrayOfJSON))
for (m = 0; m < (JSON.parse(mess[i].arrayOfJSON)).length; m++) {
console.log("almost")
console.log((JSON.parse(mess[i].arrayOfJSON))[m])
}
}
mess = [{
"name": "user1",
"arrayOfJSON": `[{"email":"Alex#gmail","hobby":"coding"},{"email":"bob#gmail","hobby":"coocking"}]`
},
{
"name": "user2",
"arrayOfJSON": `[{"email":"Chris#gmail","hobby":"coding"},{"email":"bob#gmail","hobby":"coocking"}]`
},
{
"name": "user3",
"arrayOfJSON": `[{"email":"bob#gmail","hobby":"coocking"},{"email":"Alex#gmail","hobby":"coding"}]`
}
]
console.log(mess)
holdMessPosition = []
for (i = 0; i < mess.length; i++) {
var pos = (JSON.parse(mess[i].arrayOfJSON)).map(function(e) {
return e.email;
})
.indexOf("Alex#gmail");
console.log("user position is " + pos);
if (pos !== -1) {
holdMessPosition.push(i)
}
}
console.log(holdMessPosition)
Parse your data
You want to be able to access keys inside the inner object "string"
Traverse your data
While visiting key-value pairs, build a scope thet you can later return
// Adapted from: https://gist.github.com/sphvn/dcdf9d683458f879f593
const traverse = function(o, fn, scope = []) {
for (let i in o) {
fn.apply(this, [i, o[i], scope]);
if (o[i] !== null && typeof o[i] === "object") {
traverse(o[i], fn, scope.concat(i));
}
}
}
const mess = [{
"name": "user1",
"arrayOfJSON": `[{"email":"Alex#gmail","hobby":"coding"},{"email":"bob#gmail","hobby":"coocking"}]`
}, {
"name": "user2",
"arrayOfJSON": `[{"email":"Chris#gmail","hobby":"coding"},{"email":"bob#gmail","hobby":"coocking"}]`
}, {
"name": "user3",
"arrayOfJSON": `[{"email":"bob#gmail","hobby":"coocking"},{"email":"Alex#gmail","hobby":"coding"}]`
}];
// Parse...
mess.forEach(item => {
if (item.arrayOfJSON) {
item.arrayOfJSON = JSON.parse(item.arrayOfJSON);
}
});
traverse(mess, (key, value, scope) => {
if (value === 'Alex#gmail') {
console.log(
`Position: mess[${scope.concat(key).map(k => isNaN(k) ? `'${k}'` : k).join('][')}]`
);
}
});
.as-console-wrapper {
top: 0;
max-height: 100% !important;
}

Javascript manipulating json issue

[
{
"timing": [
{
"zone": 18.8
},
{
"zone": 17.06,
},
{
"zone": 16.6
},
]
},
{
"timing": [
{
"zone": 12.6,
},
{
"zone": 14.6,
}
]
},
{
"timing": [
{
"zone":19.06,
},{
"zone": 8.06,
}
]
}
]
Here i am trying to work manipulate with one json data using javascript.
But, I am not able to think any approach how to achive that.
I am expecting below json. It give zone1, zone2, zone3 as per the zone any it will be dynamically
Please have a look to below json.
[
{
"zone1": [18.8, 12.6, 19.06 ]
},{
"zone2": [17.06, 14.6, 8.06]
}, {
"zone3":[16.6]
}
]
This is the output of json how it should look like.
Please have a look
You can use reduce and forEach
Loop through data, set OP's initial value as an object
Loop through timing property of each element, check if the zone + index + 1 exists in op or not, if exists push zone to that key else initialise new key
let data = [{"timing": [{"zone": 18.8},{"zone": 17.06,},{"zone": 16.6},]},{"timing": [{"zone": 12.6,},{"zone": 14.6,}]},{"timing": [{"zone": 19.06,}, {"zone": 8.06,}]}]
let final = data.reduce((op, { timing }) => {
timing.forEach(({ zone }, i) => {
let key = `zone${ 1 + i }`
op[key] = op[key] || []
op[key].push(zone)
})
return op
}, {})
console.log(final)
// If you need final output to be array of object just use entries and map to build a desired output
console.log(Object.entries(final).map(([k,v])=>({[k]:v})))
Here's a possible solution
var data = [{
"timing": [{
"zone": 18.8
},
{
"zone": 17.06,
},
{
"zone": 16.6
},
]
},
{
"timing": [{
"zone": 12.6,
},
{
"zone": 14.6,
}
]
},
{
"timing": [{
"zone": 19.06,
}, {
"zone": 8.06,
}]
}
];
// Calculate the total number of zones
var totalZones = 0;
for (let i = 0; i < data.length; i++) {
const currZones = data[i].timing.length;
if (currZones > totalZones) totalZones = currZones;
}
console.log(totalZones);
// Create the final Array
var result = new Array(totalZones);
for (let i = 0; i < totalZones; i++) {
result[i] = {
zone: []
}
}
// Populate the final array with values
for (let i = 0; i < totalZones; i++) {
for (let j = 0; j < data.length; j++) {
let currTiming = data[j].timing[i];
if (currTiming !== undefined) {
let currZone = data[j].timing[i].zone;
if (currZone !== undefined) {
result[i].zone.push(currZone);
}
}
}
}
console.log(result);
1) Gather all zone values into one array of array
2) Calculate max rows needed for zones
3) Have a simple for-loop till max rows and use shift and push methods.
const data = [
{
timing: [
{
zone: 18.8
},
{
zone: 17.06
},
{
zone: 16.6
}
]
},
{
timing: [
{
zone: 12.6
},
{
zone: 14.6
}
]
},
{
timing: [
{
zone: 19.06
},
{
zone: 8.06
}
]
}
];
const zones = data.map(time => time.timing.map(z => z.zone));
const rows = zones.reduce((rows, arr) => Math.max(rows, arr.length), 0);
const all = [];
for (let index = 1; index <= rows; index++) {
const res = [];
zones.forEach(zone => zone.length > 0 && res.push(zone.shift()));
all.push({ [`zone${index}`]: res });
}
console.log(all);
const input = [ {"timing": [{"zone": 18.8},{"zone": 17.06,},{"zone": 16.6},]},{"timing": [{"zone": 12.6,},{"zone": 14.6,}]},{"timing": [{"zone":19.06,},{"zone": 8.06,}]}]
var data = input.map(t => t.timing.map(u => u.zone));
var output = data[0].map((col, i) => data.map(row => row[i])).map((item, index) => {res = {}; res["zone"+(index+1)] = item.filter(t => t!==undefined); return res});
console.log(output);
Not the shortest, but it's very readable.
var json = [{"timing": [{"zone": 18.8},{"zone": 17.06,},{"zone": 16.6},]},{"timing": [{"zone": 12.6,},{"zone": 14.6,}]},{"timing": [{"zone": 19.06,}, {"zone": 8.06,}]}];
// index 0 is zone1, index 1 is zone2, index 2 is zone3, and so on ...
var zones = [];
// Loop through each 'timing' object
json.forEach(function(timingObject) {
var timing = timingObject['timing'];
// loop through each 'zone' in the given 'timing' object
timing.forEach(function(zoneObject, index) {
var zone = zoneObject['zone'];
// if the zone exists in the zones[] defined above
// add the current zone to its place
//
// if not (else), we have to add the array for the
// current index, then add the value of the current zone.
if(zones[index]) {
zones[index]['zone' + (index + 1)].push(zone);
} else {
zones.push({ ['zone' + (index + 1)]: [zone]})
}
});
});
console.log(zones);

How to create a nested object from data using JavaScript?

Before
This is an object with multiple rows:
{
"functions": [
{
"package_id": "2",
"module_id": "2",
"data_id": "2"
},
{
"package_id": "1",
"module_id": "1",
"data_id": "2"
},
{
"package_id": "2",
"module_id": "3",
"data_id": "3"
}
]
}
Desired result
I want this to return into a "nested" Object like below, without duplicates:
{
"packages": [
{
"package_id": "2",
"modules": [
{
"module_id": "2",
"data": [
{
"data_id": "2"
}
]
},
{
"module_id": "3",
"data": [
{
"data_id": "3"
}
]
}
]
},{
"package_id": "1",
"modules": [
{
"module_id": "1",
"data": [
{
"data_id": "2"
}
]
}
]
}
]
}
I've already tried loops inside loops, with constructing multiple arrays and objects. Which causes duplicates or overriding objects into single ones. Is there a more generic way to generate this with JavaScript? (It's for an Angular (6) project.
Example 1
getFunctionPackage() {
var fList = this.functionList;
var dArr = [];
var dObj = {};
var pArr = [];
var pObj = {};
var mArr = [];
var mObj = {};
for (var key in fList) {
pObj['package_id'] = fList[key]['package_id'];
mObj['module_id'] = fList[key]['module_id'];
dObj['data_id'] = fList[key]['data_id'];
for (var i = 0; i < pArr.length; i++) {
if (pArr[i].package_id != pObj['package_id']) {
pArr.push(pObj);
}
for (var x = 0; x < mArr.length; x++) {
if (pArr[i]['modules'][x].module_id != mObj['module_id']) {
mArr.push(mObj);
}
for (var y = 0; y < dArr.length; y++) {
if (pArr[i]['modules'][x]['datas'][y].data_id != dObj['data_id']) {
dArr.push(dObj);
}
}
}
}
if (dArr.length == 0) {
dArr.push(dObj);
}
mObj['datas'] = dArr;
if (mArr.length == 0) {
mArr.push(mObj);
}
pObj['modules'] = mArr;
if (pArr.length == 0) {
pArr.push(pObj);
}
dObj = {};
mObj = {};
pObj = {};
}
}
Example 2:
Results in skipping cause of the booleans
var fList = this.functionList;
var dArr = [];
var dObj = {};
var pArr = [];
var pObj = {};
var mArr = [];
var mObj = {};
var rObj = {};
for (var key in fList) {
pObj['package_id'] = fList[key]['package_id'];
mObj['module_id'] = fList[key]['module_id'];
dObj['data_id'] = fList[key]['data_id'];
var pfound = false;
var mfound = false;
var dfound = false;
for (var i = 0; i < pArr.length; i++) {
if (pArr[i].package_id == pObj['package_id']) {
for (var x = 0; x < mArr.length; x++) {
if (pArr[i]['modules'][x].module_id == mObj['module_id']) {
for (var y = 0; y < dArr.length; y++) {
if (pArr[i]['modules'][x]['datas'][y].data_id == dObj['data_id']) {
dfound = true;
break;
}
}
mfound = true;
break;
}
}
pfound = true;
break;
}
}
if (!dfound) {
dArr.push(dObj);
mObj['datas'] = dArr;
dObj = {};
}
if (!mfound) {
mArr.push(mObj);
pObj['modules'] = mArr;
mObj = {};
}
if (!pfound) {
pArr.push(pObj);
pObj = {};
}
dArr = [];
mArr = [];
}
rObj['packages'] = pArr;
console.log(rObj);
Here's a more generic approach using Array#reduce() to create a grouped object based on the package id as keys. You can use any loop to build this same object ...for() or forEach() for example.
Then use Object.values() to get the final array from that grouped object
Using methods like Array#find() simplifies traversing to see if a module exists already or not within each package
const grouped = data.functions.reduce((a, c )=>{
// if group object doesn't exist - create it or use existing one
a[c.package_id] = a[c.package_id] || {package_id : c.package_id, modules: [] }
// store reference to the group modules array
const mods = a[c.package_id].modules
// look within that group modules array to see if module object exists
let module = mods.find(mod => mod.module_id === c.module_id)
if(!module){
// or create new module object
module = {module_id: c.module_id, data:[]}
// and push it into modules array
mods.push(module);
}
// push new data object to module data array
module.data.push({data_id: c.data_id})
return a
}, {})
// create final results object
const res = { packages : Object.values(grouped) }
console.log(res)
.as-console-wrapper {max-height: 100%!important;}
<script>
const data = {
"functions": [{
"package_id": "2",
"module_id": "2",
"data_id": "2"
},
{
"package_id": "1",
"module_id": "1",
"data_id": "2"
},
{
"package_id": "2",
"module_id": "3",
"data_id": "3"
}
]
}
</script>

check to see if all objects in an array has a common property

I have an array of objects which I am trying to loop over and check for a common key if it exists for all objects. if the specific key does not exist for all objects I return false.
Here is my code
var x = [{
"item": "alpha",
"value": "red"
}, {
"item": "beta",
"value": "blue"
}, {
"item": "beta",
"value": "gama"
}]
function test(obj) {
var count = 0;
var out = false;
for (var i = 0; i < obj.length; i++) {
if (obj[i].hasOwnProperty('value')) {
count = i;
}
}
if (count == obj.length) {
out = true
}
}
console.log(test(x))
I am getting undefined. Cant figure out what am I missing here
A really simple way to do this is to use Array#every like this
var x = [{
"item": "alpha",
"value": "red"
}, {
"item": "beta",
"value": "blue"
}, {
"item": "beta",
"value": "gama"
}]
function test(obj) {
return obj.every(a => a.hasOwnProperty("value"));
}
console.log(test(x))
Update
As rightfully mentioned by this comment first.
Here can be the simple solution for this object:
var x = [{
"item": "alpha",
"value": "red"
}, {
"item": "beta",
"value": "blue"
}, {
"item": "beta",
"value": "gama"
}];
function test(obj) {
var keyCount = 0;
obj.forEach(function (item, index) {
item.hasOwnProperty('value') && ++keyCount;
});
return keyCount == obj.length;
}
console.log(test(x));
Here is my implementation, which finds every matching key, even nested keys, given a set of objects:
function recurse_obj(obj, cb, _stack = []) {
for (var k in obj) {
cb(k, obj[k], _stack);
if (obj.hasOwnProperty(k) && (obj[k] instanceof Object)) {
_stack.push(k);
recurse_obj(obj[k], cb, _stack);
_stack.pop();
}
}
}
function obj_all_keys(obj) {
var tmp = [];
recurse_obj(obj, (k, v, stack) => {
var ext = (stack.length) ? "." : "";
tmp.push(stack.join(".").concat(ext, k));
});
return tmp;
}
function key_intersection(...objs) {
var lookup = {};
objs.forEach(o => {
obj_all_keys(o).forEach(k => {
if (k in lookup === false)
lookup[k] = 0;
lookup[k]++;
});
});
for (var k in lookup)
if (lookup[k] !== objs.length)
delete lookup[k];
return lookup;
}
Here is the calling code:
var me = { name: { first: "rafael", last: "cepeda" }, age: 23, meta: { nested: { foo: { bar: "hi" } } } };
console.log(key_intersection(me, { name: { first: "hi" } }));
Output: { name: 2, 'name.first': 2 }
The object returned includes only the keys that are found in all the objects, the set intersection, the counts are from book-keeping, and not removed in the callee for performance reasons, callers can do that if need be.
Keys that are included in other nested keys could be excluded from the list, because their inclusion is implied, but I left them there for thoroughness.
Passing a collection (array of objects) is trivial:
key_intersection.apply(this, collection);
or the es6 syntax:
key_intersection(...collection);

Push Unique Objects to JavaScript Array

How do I push an object into an specified array that only updates that array? My code pushes an object and updates all arrays, not just the specified one.
Here is the structure of the data:
{
"d": {
"results": [
{
"Id": 1,
"cost": "3",
"item": "Project 1",
"fiscalyear": "2014",
"reportmonth": "July"
}
]
}
}
Here is a sample of the desired, wanted results:
{
"Project 1": [
{
"date": "31-Jul-14",
"rating": "3"
},
{
"date": "31-Aug-14",
"rating": "4"
}
],
"Project 2": [
{
"date": "31-Jul-14",
"rating": "2"
}
]
}
This is my attempt:
var results = data.d.results;
var date;
var projectObj = {},
projectValues = {},
project = '';
var cost = '',
costStatus = '';
for (var i = 0, m = results.length; i < m; ++i) {
project = results[i]['item'];
if (!projectObj.hasOwnProperty(project)) {
projectObj[project] = [];
}
// use Moment to get and format date
date = moment(new Date(results[i]['reportmonth'] + ' 1,' + results[i]['fiscalyear'])).endOf('month').format('DD-MMM-YYYY');
// get cost for each unique project
costStatus = results[i]['cost'];
if (costStatus == null || costStatus == 'N/A') {
cost = 'N/A';
}
else {
cost = costStatus;
}
projectValues['rating'] = cost;
projectValues['date'] = date;
projectObj[project].push(projectValues);
}
Here is a Fiddle with the undesired, unwanted results:
https://jsfiddle.net/yh2134jn/4/
What am I doing wrong?
That is because You do not empty it new iteration. Try this:
for (var i = 0, m = results.length; i < m; ++i) {
projectValues = {};
project = results[i]['item'];
....
}

Categories