group dates by week javascript - javascript

I have the array of Persian dates and I want to group dates by the week.
for example, I have the following array:
[
"1396-10-11 09:07:21",
"1396-10-10 10:03:51",
"1396-10-07 02:07:02",
"1396-11-27 08:02:45",
"1396-11-19 01:02:32",
"1396-12-01 22:13:21",
"1396-02-12 09:07:21",
"1396-05-18 04:02:29",
"1396-05-21 14:01:42",
"1396-07-11 01:16:29"
]
and I want to groupBy dates by the week.
I wrote following code but not working good:
Array.prototype.groupBy = function(prop) {
return this.reduce(function(groups, item) {
var val = item[prop];
groups[val] = groups[val] || [];
groups[val].push(item);
return groups;
}, {});
}
const formatted = dates.map(elem => {
return {
numberOfWeek: moment(elem.date, 'jYYYY-jMM-jDD').startOf('jMonth').jWeek(),
date: moment(elem.date, 'jYYYY-jMM-jDD').format('jYYYY-jMM-jDD'),
score: elem.score
};
});

You can use moment().week() to get the week number of the year and then group by it, here is a working example, I used array.reduce to create a new object of dates grouped by the week number:
const dates = [
"1396-10-11 09:07:21",
"1396-10-10 10:03:51",
"1396-10-07 02:07:02",
"1396-11-27 08:02:45",
"1396-11-19 01:02:32",
"1396-12-01 22:13:21",
"1396-02-12 09:07:21",
"1396-05-18 04:02:29",
"1396-05-21 14:01:42",
"1396-07-11 01:16:29"
];
const groups = dates.reduce((acc, date) => {
// create a composed key: 'year-week'
const yearWeek = `${moment(date).year()}-${moment(date).week()}`;
// add this key as a property to the result object
if (!acc[yearWeek]) {
acc[yearWeek] = [];
}
// push the current date that belongs to the year-week calculated befor
acc[yearWeek].push(date);
return acc;
}, {});
console.log(groups);
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.20.1/moment.min.js"></script>

Another simple way of achieving the same with Lodash would be as follows:
const groupBy = require('lodash/groupBy');
const moment = require('moment');
const data = [
"1396-10-11 09:07:21",
"1396-10-10 10:03:51",
"1396-10-07 02:07:02",
"1396-11-27 08:02:45",
"1396-11-19 01:02:32",
"1396-12-01 22:13:21",
"1396-02-12 09:07:21",
"1396-05-18 04:02:29",
"1396-05-21 14:01:42",
"1396-07-11 01:16:29"
];
groupBy(data, (dt) => moment(dt).week());
Result is as follows:
{
'7': [ '1396-02-12 09:07:21' ],
'21': [ '1396-05-18 04:02:29', '1396-05-21 14:01:42' ],
'29': [ '1396-07-11 01:16:29' ],
'41': [ '1396-10-07 02:07:02' ],
'42': [ '1396-10-11 09:07:21', '1396-10-10 10:03:51' ],
'47': [ '1396-11-19 01:02:32' ],
'49': [ '1396-11-27 08:02:45', '1396-12-01 22:13:21' ]
}

Related

How to get the object only from array in javascript?

I want to achieve this format. As you can see on the output there's a bracket but I want to get only the '10': ["11/21/2022", "11/25/2022"] or this one.
{
'10': ["11/21/2022", "11/25/2022"]
}
const data = [{
user_id: "10",
dates: ["11/21/2022", "11/25/2022"],
}, ];
const output = data.map(({
user_id,
dates
}) => ({
[user_id]: dates
}));
console.log(output);
You can only do this if the array has just one entry. Otherwise, how would you know which array element to use?
Then just create it directly, map creates an array, not an object:
const [{ user_id, dates }] = data;
const output = {
[user_id]: dates,
};
Live Example:
const data = [
{
user_id: "10",
dates: ["11/21/2022", "11/25/2022"],
},
];
const [{ user_id, dates }] = data;
const output = {
[user_id]: dates,
};
console.log(output);
Or without the initial destructuring:
const output = {
[data[0].user_id]: data[0].dates,
};
Live Example:
const data = [
{
user_id: "10",
dates: ["11/21/2022", "11/25/2022"],
},
];
const output = {
[data[0].user_id]: data[0].dates,
};
console.log(output);
map is returning array again, so if you wanna get only object you can use [0] to access it directly
sth like this :
console.log(output[0]);
or this :
const output = data.map(({
user_id,
dates
}) => ({
[user_id]: dates
}))[0];

Lodash create object from array of arrays

I would like to use lodash to generete object from array of arrays. I use for it lodash.zipObject method and map. But it is not 1:1 what I would like to generate:
Input:
"rows": [
[
"stravi/aa",
"202001",
"59",
"51",
"2558.98",
"0.5358894453719162",
"1.9204668112983725",
"140",
"2.3466309084813943"
],
[
"stravi/ab",
"202003",
"3591",
"349",
"2246.09",
"0.41838214",
"3.57603358",
"50",
"4.82115474"
],
[
"stravi/ac",
"202007",
"3354",
"25",
"1975.76",
"0.74220667708",
"1.12321555541",
"11",
"0.9324532454"
]
]
dictionary: ['source', 'sessions', 'adClicks', 'adCost', 'CPC', 'CTR', 'goalCompletionsAll', 'goalConversionRateAll' ], [action.yearReportData]
output:
{
source: ['stravi/aa', 'stravi/ab', 'stravi/ac'],
sessions: ['202001', '202003', '202007']
...
}
I would like to use lodash, and I try by:
lodash.map(rows, arr =>
lodash.zipObject(['source', 'sessions', 'adClicks', 'adCost', 'CPC', 'CTR', 'goalCompletionsAll', 'goalConversionRateAll'], arr))
But is not correct... I received multiple object. I would like to have one object with all data. Like my example.
Unzip the rows to transpose the sub-arrays, and then use zip object:
const { flow, unzip, zipObject } = _
const fn = flow(
unzip,
arr => zipObject(['source', 'sessions', 'adClicks', 'adCost', 'CPC', 'CTR', 'goalCompletionsAll', 'goalConversionRateAll'], arr)
)
const rows = [["stravi/aa","202001","59","51","2558.98","0.5358894453719162","1.9204668112983725","140","2.3466309084813943"],["stravi/ab","202003","3591","349","2246.09","0.41838214","3.57603358","50","4.82115474"],["stravi/ac","202007","3354","25","1975.76","0.74220667708","1.12321555541","11","0.9324532454"]]
const result = fn(rows)
console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.js"></script>
why use third-party library, if may easy do it like so
let result = rows.reduce((obj, arr) => {
arr.forEach((item, i) => {
if (!obj[dictionary[i]]) {
obj[dictionary[i]] = [];
}
obj[dictionary[i]].push(item);
})
return obj;
}, {});
You need a reducer instead of map. Map just transform each elements that is why you get multiple elements.
I would use plain JS for this one. It will look like this:
const rows = [
[
'stravi/aa',
'202001',
'59',
'51',
'2558.98',
'0.5358894453719162',
'1.9204668112983725',
'140',
'2.3466309084813943',
],
[
'stravi/ab',
'202003',
'3591',
'349',
'2246.09',
'0.41838214',
'3.57603358',
'50',
'4.82115474',
],
[
'stravi/ac',
'202007',
'3354',
'25',
'1975.76',
'0.74220667708',
'1.12321555541',
'11',
'0.9324532454',
],
];
const keys = [
'source',
'sessions',
'adClicks',
'adCost',
'CPC',
'CTR',
'goalCompletionsAll',
'goalConversionRateAll',
'missingFieldName',
];
const initialAcc = keys.reduce((acc, cur) => {
acc[cur] = [];
return acc;
}, {});
const resultAcc = rows.reduce((acc, cur) => {
cur.forEach((value, index) => acc[keys[index]].push(value));
return acc;
}, initialAcc);
console.log(resultAcc);

How do I get the latest timestamp for each month in an array

I have an array with a bunch of objects and some key/value pairs + timestamp (moment.js formatted timestamp) in it.
I have many timestamps for 12 months in total and need to get the last timestamp for each month and drop the other objects.
Actually I don't even know how to start off.
I used _.sortBy to order the array by date already but don't know how to move on.
array1 = [
{name:name1,timestamp:2018-09-15T07:00:00.0},
{name:name2,timestamp:2018-09-15T12:00:00.0},
{name:name3,timestamp:2018-09-28T05:00:00.0},
{name:name4,timestamp:2018-09-30T01:00:00.0},
{name:name5,timestamp:2018-10-02T10:00:00.0},
{name:name6,timestamp:2018-10-02T11:00:00.0},
{name:name7,timestamp:2018-10-15T07:00:00.0},
{name:name8,timestamp:2018-12-05T08:00:00.0},
{name:name9,timestamp:2018-12-05T09:00:00.0},
{name:name10,timestamp:2018-12-05T10:00:00.0}
]
expected result is
array1 = [
{name:name4,timestamp:2018-09-30T01:00:00.0},
{name:name7,timestamp:2018-10-15T07:00:00.0},
{name:name10,timestamp:2018-12-05T10:00:00.0}
]
reduce the array to an object having months as keys, overwriting they keys evrytime you find them, then your result is the array of Object.values` :
const array1 = [
{ name: "name1", timestamp: "2018-09-15T07:00:00.0" },
{ name: "name2", timestamp: "2018-09-15T12:00:00.0" },
{ name: "name3", timestamp: "2018-09-28T05:00:00.0" },
{ name: "name4", timestamp: "2018-09-30T01:00:00.0" },
{ name: "name5", timestamp: "2018-10-02T10:00:00.0" },
{ name: "name6", timestamp: "2018-10-02T11:00:00.0" },
{ name: "name7", timestamp: "2018-10-15T07:00:00.0" },
{ name: "name8", timestamp: "2018-12-05T08:00:00.0" },
{ name: "name9", timestamp: "2018-12-05T09:00:00.0" },
{ name: "name10", timestamp: "2018-12-05T10:00:00.0" }
];
const result = array1.reduce((acc, curr) => {
const month = new Date(curr.timestamp).getMonth() + 1;
acc[month] = curr;
return acc;
}, {});
console.log(Object.values(result));
You could take the date part, and store each entry in a hastable under that date. Thus, every entry with the same month will override the previous one, and the last one will be kept:
const byMonth = {};
for(const { name, timestamp } of array1) {
const month = timestamp.slice(0, 7);
byMonth[month] = { name, timestamp };
}
const result = Object.values(byMonth);
const array1 = [
{name:"name1",timestamp:"2018-09-15T07:00:00.0"},
{name:"name2",timestamp:"2018-09-15T12:00:00.0"},
{name:"name3",timestamp:"2018-09-28T05:00:00.0"},
{name:"name4",timestamp:"2018-09-30T01:00:00.0"},
{name:"name5",timestamp:"2018-10-02T10:00:00.0"},
{name:"name6",timestamp:"2018-10-02T11:00:00.0"},
{name:"name7",timestamp:"2018-10-15T07:00:00.0"},
{name:"name8",timestamp:"2018-12-05T08:00:00.0"},
{name:"name9",timestamp:"2018-12-05T09:00:00.0"},
{name:"name10",timestamp:"2018-12-05T10:00:00.0"}
];
const byMonth = {};
for(const { name, timestamp } of array1) {
const month = timestamp.slice(0, 7);
byMonth[month] = { name, timestamp };
}
const result = Object.values(byMonth);
console.log(result);

Flatten an array of objects and get unique keys and values by a repeated date with Lodash?

I've been playing around with Lodash and not getting close to a solution that doesn't involve a lot of extra looping and overhead.
data: [
{
name: "FirstResult", values: [
{
value: { NameCount: 1, OtherCount: 1 },
date: 2019-05-15T07:00:00+0000
},
{
value: { NameCount: 1 },
date: 2019-05-16T07:00:00+0000
}
]
},
{
name: "SecondResult",
values: [
{
value: { NameCount: 1 },
date: 2019-05-15T07:00:00+0000
},
{
value: { BuyCount: 2, SellCount: 1 },
date: 2019-05-16T07:00:00+0000
}
]
}
]
I'd like to flatten this and have it combined and aggregated by using the date as the key returning some configuration like:
[
{ date: 2019-05-15T07:00:00+0000, values: { NameCount: 2, OtherCount: 1 } },
{ date: 2019-05-16T07:00:00+0000, values: { NameCount: 1, BuyCount: 2, SellCount: 1 } }
]
Or even just a flat object array is fine like:
[
{ date: 2019-05-15T07:00:00+0000, NameCount: 2, OtherCount: 1 },
{ date: 2019-05-16T07:00:00+0000, NameCount: 1, BuyCount: 2, SellCount: 1 }
]
Does anyone have any ideas on how to do this with either a Lodash or Vanilla solution?
You can use a lodash's chain to flatten, group by the date, and then map and merge each group to a single object:
const fn = data => _(data)
.flatMap('values') // flatten to array of objects
.groupBy(o => o.date.toISOString()) // group by the iso representation
.map(group => { // map the groups by merging, and converting to require format
const { date, value } = _.mergeWith({}, ...group, (objValue, srcValue) =>
_.isNumber(objValue) ? objValue + srcValue : undefined // combine numeric values
)
return {
date,
...value,
}
})
.value()
const data = [{"name":"FirstResult","values":[{"value":{"NameCount":1,"OtherCount":1},"date": new Date("2019-05-15T07:00:00.000Z")},{"value":{"NameCount":1},"date": new Date("2019-05-16T07:00:00.000Z")}]},{"name":"SecondResult","values":[{"value":{"NameCount":1},"date":new Date("2019-05-15T07:00:00.000Z")},{"value":{"BuyCount":2,"SellCount":1},"date": new Date("2019-05-16T07:00:00.000Z")}]}]
const result = fn(data)
console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.js"></script>
Or you can use _.flow() to generate the function (I'm using lodash/fp here):
const { flow, flatMap, groupBy, map, mergeAllWith, cond, isNumber, add } = _
const fn = flow(
flatMap('values'), // flatten to array of objects
groupBy(o => o.date.toISOString()), // group by the iso representation
map(mergeAllWith(cond([[isNumber, add]]))), // combine numeric values
map(({ date, value }) => ({ date, ...value })) // format the objects
)
const data = [{"name":"FirstResult","values":[{"value":{"NameCount":1,"OtherCount":1},"date": new Date("2019-05-15T07:00:00.000Z")},{"value":{"NameCount":1},"date": new Date("2019-05-16T07:00:00.000Z")}]},{"name":"SecondResult","values":[{"value":{"NameCount":1},"date":new Date("2019-05-15T07:00:00.000Z")},{"value":{"BuyCount":2,"SellCount":1},"date": new Date("2019-05-16T07:00:00.000Z")}]}]
const result = fn(data)
console.log(result)
<script src='https://cdn.jsdelivr.net/g/lodash#4(lodash.min.js+lodash.fp.min.js)'></script>
Here is pure ES6 solution based on Array.reduce and Array.forEach for the object keys:
const data = [{"name":"FirstResult","values":[{"value":{"NameCount":1,"OtherCount":1},"date": new Date("2019-05-15T07:00:00.000Z")},{"value":{"NameCount":1},"date": new Date("2019-05-16T07:00:00.000Z")}]},{"name":"SecondResult","values":[{"value":{"NameCount":1},"date":new Date("2019-05-15T07:00:00.000Z")},{"value":{"BuyCount":2,"SellCount":1},"date": new Date("2019-05-16T07:00:00.000Z")}]}]
let result = data.reduce((r, { values }) => {
values.forEach(({ value, date }) => {
let keys = Object.keys(value), d = date.toISOString()
r[d] = r[d] || Object.assign({}, ...keys.map(x => ({ date: d, [x]: 0 })))
keys.forEach(k => r[d][k] = (r[d][k] || 0) + value[k])
})
return r
}, {})
console.log(Object.values(result))
The main idea is to get the keys of the value object white iterating and compose an object with them while grouping by the date. Then last forEach just sums each result object value.

Javascript mapping

In our project we are getting below data from DB in following format.
[
[
"ClearDB",
"test1#test.com",
"com.test.cleardb"
],
[
"Cricbuzz",
"test2#test.com",
"com.test.cricbuzz"
],
[
"Hangout",
"test3#test.com",
"com.test.hangout"
]
]
I want this in key value format as mentioned below
[
{
"projname": "ClearDB",
"projmanager": "test1#test.com",
"package": "com.test.cleardb"
},
{
"projname": "Cricbuzz",
"projmanager": "test2#test.com",
"package": "com.test.cricbuzz"
},
{
"projname": "Hangout",
"projmanager": "test3#test.com",
"package": "com.test.hangout"
}
]
Please provide me a proper way to implement this.
You can simply create a new object for each of the arrays, and create an array of objects with map function, like this
var keys = ["projname", "projmanager", "package"];
console.log(data.map(function (arr) {
var obj = {};
keys.forEach(function (key, idx) { obj[key] = arr[idx]; });
return obj;
}));
Output
[ { projname: 'ClearDB',
projmanager: 'test1#test.com',
package: 'com.test.cleardb' },
{ projname: 'Cricbuzz',
projmanager: 'test2#test.com',
package: 'com.test.cricbuzz' },
{ projname: 'Hangout',
projmanager: 'test3#test.com',
package: 'com.test.hangout' } ]
with Array.prototype.map:
var results = db.map(function (v) {
return {
projname: v[0],
projmanager: v[1],
package: v[2]
};
});
Suppose the data you are getting from database is stored in variable 'abc'
var abc = [];
var output = [];
for(var i = 0; i< abc.length; i++){
output[i] = {};
output[i].projname = abc[i][0];
output[i].projmanager = abc[i][1];
output[i].package = abc[i][2];
}
Note: 'abc' is the variable where you are storing data from DB.
In ES6:
input . map(([projname, projmanager, package]) => ({projname, projmanager, package}));
The part in [] deconstructs the parameter to map, which is one of the subarrays, assigning the first element to projname, and so on. The part in {} creates and returns an object with a key of 'projname' whose value is projname, etc.
If you want to generalize this to use any array of field names (['projname', 'projmanager', 'package']):
input . map(
values =>
values . reduce(
(result, value, i) => {
result[fieldnames[i]] = value;
return result;
},
{}
)
);
if
var array =[
[
"ClearDB",
"test1#test.com",
"com.test.cleardb"
],
[
"Cricbuzz",
"test2#test.com",
"com.test.cricbuzz"
],
[
"Hangout",
"test3#test.com",
"com.test.hangout"
]
];
then
var obj = [];
array.each(function(item){ obj.push({"projname": item[0],
"projmanager":item[1],
"package": item[2]})
});
Edit:
Using Jquery
var obj = [];
$.each(array,function(key,value){ obj.push({"projname": value[0],
"projmanager":value[1],
"package": value[2]})
});
Using javascript
var obj = [];
array.forEach(function(item){ obj.push({"projname": item[0],
"projmanager":item[1],
"package": item[2]})
});

Categories

Resources