I have an array in my state and I want to set array specific values to its objects.
The code looks like this:
state = {
course: "",
type: "",
days: [
{
day: "",
rstime: "",
retime: "",
}
],
}
createSchedule = () => {
const { course,
module,
days
} = this.state;
data.push({
course,
module,
days[]
})
}
For now, I am able to set the state of course and module. I want to know how to set the days so that a course can have multiple days and different times.
The output should look like this for instance:
Course: Biology
Type: Lecture
days:
{
Monday
09:30
11:40
}
{
Friday
15:30
16:40
}
You can something like this,
const days = [...this.state.days];
days.push({
Friday
15:30
16:40
});
this.setState({days});
Related
This is a calendar check. For example: 100 days of history is available but 101 days back would be disabled for certain market.
Code is following:
const todaysDate3 = dayjs().subtract(101, 'days').format('DD')
const todaysDate4 = dayjs().subtract(100, 'days').format('DD') //etc
cy.visit(`http://calendar.whatever/ICN&markettype=ICN`);
cy.get('.calendar-table').click
cy.get('.calendar-table').contains('td',(todaysDate3)).should("have.class","disabled")
cy.get('.calendar-table').contains('td',(todaysDate4)).should("have.class","enabled")
What would be the best practice to make such test for 80, 100, 365 etc days as every market. Worst case scenario I can think of is something like
export const 100days = [{
"url": (`http://calendar.whatever/ICN`),
"has100days": true
}]
and like this for every possible value and using
if (curr.has100days) //do something } else if (curr.has365days){do something else}
Probably best would be to write some kind of function?
thank you for your help!
Since you visit each market, the data-driven approach you indicate is best.
const history = [
{ market: 'ICN', days: 100 },
{ market: 'ZYX', days: 120 },
...
]
history.forEach(data => {
cy.log(`Testing ${data.market} with ${data.days} history`)
cy.visit(`http://calendar.whatever/ICN&markettype=${data.market}`)
const outsideHistory = dayjs().subtract(data.days+1, 'days')
.format('D') // no leading '0'
const insideHistory = dayjs().subtract(data.days, 'days')
.format('D') // no leading '0'
const outsideHistoryRegex = new RegExp(`^${outsideHistory}`) // ^ = startsWith
const insideHistoryRegex = new RegExp(`^${insideHistory}`)
cy.get('.calendar-table').click
cy.get('.calendar-table').contains('td', outsideHistoryRegex)
.last()
.should("have.class","disabled")
cy.get('.calendar-table').contains('td', insideHistoryRegex)
.last()
.should("have.class","enabled")
}
I'm assuming you only want to check the history boundary for each market, but if you want to check multiple dates per market
const history = [
{ market: 'ICN', days: 85 },
{ market: 'ICN', days: 100 },
{ market: 'ICN', days: 365 },
{ market: 'ZYX', days: 120 },
...
]
// Same function...
You can do something like this:
cy.get('.calendar-table')
.find('td')
.then(($ele) => {
if ($ele.text().includes(todaysDate3)) {
cy.wrap($ele).should('have.class', 'disabled')
//Do Something
} else if ($ele.text().includes(todaysDate4)) {
cy.wrap($ele).should('have.class', 'enabled')
//Do Something
} else {
//Do something
}
})
I am currently creating an animal shelter web app using mern and i have trouble grouping data by date month. so i have this schema for the rescued date:
const animalSchema = new mongoose.Schema({
date_rescued: {
type: Date,
default: Date.now,
},
})
module.exports = mongoose.model('Animal', animalSchema);
And here on my animal controller backend this is my query for fetching the datas:
exports.getRescuedChart = async(req,res,next) => {
const rescuedanimals = await Animal.find({}).select(['date_rescued']);
res.status(200).json({
success:true,
rescuedanimals,
})
}
the data that this function is returning to the state is this:
what i want to have is group them by data and count how many object has the same date.
rescuedanimals =[
{
date_rescued: "April",
animal_count: 8
}
]
so yeah i just learn how to do it myself so here's what i did.
first is that i installed dataeformat library: 'npm install dateformat'
i import it on my project: import dateFormat from 'dateformat';
what i did first is to change the date format and reduce duplicate dates.
const groups = rescuedanimals.reduce(
(groups, rescued_animal) => {
const date = dateFormat(rescued_animal.date_rescued[0], "mmmm")
if (!groups[date]) {
groups[date]=[]
}
groups[date].push(rescued_animal);
return groups;
}, {}
)
after that i created a new function to put this on an arraay and also to get the legnth of the objects that are in that date.
const groupArrays = Object.keys(groups).map((date) => {
return {
date,
games: groups[date].length
};
});
thanks to Austin Greco: https://stackoverflow.com/a/46802505/12398637
I have a reduce function that is building multiple levels and is working perfectly for me except for one issue
Currently, it's building data based on employee first, then by date, area, and job. I'm getting all of the data at the proper level but I'm now trying to aggregate certain data for a totals section at the date level and it's just listing values rather than aggregating.
Basically, in the line I've notated below, I'd like to create a value called total_scans that simply adds up ALL scans for any orders on that date. In other words, for the record for Miranda on 8/12 I would expect the total_scans at the date level to have 49 as the value. Am I on the right track?
const nest = (rows) =>
rows.reduce(
(a, row) => {
const employee = a[row.employee] || (a[row.employee] = { dates: {} })
const date = employee.dates[row.job_date] || (employee.dates[row.job_date] = { areas: {} })
const order = date.areas[row.area_number] || (date.areas[row.area_number] = { jobs: {} })
const job = order.jobs[row.job] || (order.jobs[row.job] = { hours: '', scans: '', job_date: '' })
job.hours += row.hours
job.scans += row.scans
job.job_date = row.job_date
//this line is my issue
date.total_scans += job.scans
return a
},
{}
);
new Vue({
el: "#app",
props: {
},
data: {
rows: [
{
employee: "Miranda",
job: "123",
hours: "10",
job_date: "08/12/2021",
scans: 37,
area_number: "1234567",
},
{
employee: "Miranda",
job: "167",
hours: "15",
scans: 12,
job_date: "08/12/2021",
area_number: "1234568",
},
{
employee: "Miranda",
job: "184",
hours: "18",
scans: 24,
job_date: "08/13/2021",
area_number: "1234569",
}
],
},
computed: {
numbersByEmployee() {
return nest(this.rows)
},
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
{{numbersByEmployee}}
</div>
Your usage of reduce is a little irregular. The idea of reduce is to take an iterable (array) and return a single value, usually something like a String or Number.
Also, you're causing all sorts of side effects in your reducer, by modifying the object and arrays. Since Javascript is pass-by-reference for arrays and objects, those changes you're causing will be reflected in the original object, which is not how Vue prescribes things are done. If you want to modify data, it should be done in a watch, not a computed.
Finally, I believe you're overcomplicating your reduce function. Instead of a long reduce like that, you could simply do the below. Note the initialValue of 0.
const nest = (rows) =>
rows.reduce(
(sum, row) => {
return sum + row['scans'];
},
0
);
Obviously this will count all scans. If you want to only count scans by date, how about save yourself running the reducer across the array, and instead run filter first? Something like
const nest = (rows) =>
rows.filter(({job_date}) => job_date === SomeDate).reduce(...)
The {job_date} is a destructuring assignment. You could also split out a date filtered array into its own computed.
I have collected an array of weather data that looks like this:
const data = [{
"city_name": "London",
"lat": 51.507351,
"lon": -0.127758,
"main": {
"temp": 289.89,
"temp_min": 288.468,
"temp_max": 291.15,
"feels_like": 287.15,
"pressure": 1004,
"humidity": 77
},
"wind": { "speed": 5.1, "deg": 230 },
"clouds": { "all": 90 },
"weather": [
{
"id": 804,
"main": "Clouds",
"description": "overcast clouds",
"icon": "04n"
}
],
"dt": 1593561600,
"dt_iso": "2020-07-01 00:00:00 +0000 UTC",
"timezone": 3600
},
...
];
This data continues in ascending date order (hour by hour), for the last 40 years.
(sample: https://pastebin.com/ciHJGhnq ) - the entire dataset is over 140MB.
From this data, I'd like to obtain the average temperature (object.main.temp) for each Month and Week of month, across the entire dataset.
The question I am trying to answer with my data is:
What is the average temperature for January, across the last 40 years.
What is the average temperature for February, across the last 40 years.
...
(get the temperature of each week in January and divide by the number of weeks, repeat for all of the other Januaries in the dataset and average that out too).
Repeat for remaining months.
The output I am aiming to create after parsing the data is:
{
[
"JANUARY": {
"weekNumber": {
"avgWeekTemp": 100.00
}
"avgMonthTemp": 69.00,
...
},
...
]
}
The city name & structure of the objects are always the same, in this case London.
// build a unique number of months
// work through our data to work out the week numbers
// work through the data once again and place the data in the right week inside finalOutput
// work through the final output to determine the average values
Unfortunately I'm not very proficient in JavaScript, so I couldn't get past the second obstacle:
"use strict";
const moment = require("moment");
const data = require("./data.json");
let months = [
{
January: [],
},
{
February: [],
},
{
March: [],
},
{
April: [],
},
{
May: [],
},
{
June: [],
},
{ July: [] },
{ August: [] },
{ September: [] },
{ October: [] },
{ November: [] },
{ December: [] },
];
const finalOutput = [];
finalOutput.push(...months);
data.forEach((object) =>
finalOutput.forEach((month) => {
if (
Object.keys(month)[0] === moment(new Date(object.dt_iso)).format("MMMM")
) {
[month].push(object.dt_iso);
}
})
);
console.log(finalOutput);
Which only returned the array of months with nothing in each month.
[
{ January: [] },
{ February: [] },
{ March: [] },
{ April: [] },
{ May: [] },
{ June: [] },
{ July: [] },
{ August: [] },
{ September: [] },
{ October: [] },
{ November: [] },
{ December: [] }
]
How can I calculate the average values per week & month across my entire data set?
I'm going to write your script for you, but while you wait here's some high-level guidance.
First, let's study your data. Each row is an hourly weather measurement. As a result, each datapoint you want will be an aggregate over a set of these rows. We should organize the script along those lines:
We'll write a function that accepts a bunch of rows and returns the arithmetic mean of the temperatures of those rows: function getAvgTemp(rows) => Number
We'll write another function that takes a bunch of rows, plus the desired month, and returns all the rows for just that month: function getRowsByMonth(month) => Array(rows)
We'll write another function that takes a bunch of rows, plus the desired week number, and returns all the rows for just that week: function getRowsByWeekNumber(rows, weekNumber) => Array(rows)
^^ that's if "week number" means 1-52. But if "week number" means "week within the month," then instead we'll do:
A function will also take a month: function getRowsByMonthWeek(rows, month, weekNumber) => Array(rows)
From these basic building blocks, we can write a routine that assembles the data you want.
What would that routine look like?
Probably something like this:
Loop through all the months of the year. We won't look in the data for these months, we'll hard-code them.
For each month, we'll call getRowsByMonth on the full data set. Call this set monthRows.
We'll pass monthRows to getAvgTemp -- it doesn't care what the timespan is, it just extracts and crunches the temp data it receives. That's our avgMonthTemp solved for.
Depending on what you mean by "week number," we'll divide the monthRows into smaller sets and then pass each set into getAvgTemp. (The hardest part of your script will be this division logic, but that's not to say it will be that hard.) This gives us your weekly averages.
We'll assemble these values into a data structure and insert it into the final structure that ultimately gets returned/logged.
Here's the implementation. It's a little different than I expected.
The biggest change is that I did some pre-processing up front so that the date values don't have to be parsed multiple times. While doing that, I also calculate each row's weekNumber. As a consequence, the week logic took the form of grouping rows by their weekNumbers rather than querying the dataset by weekNumber.
Some notes:
I decided that "weekNumber" means "week-of-year."
Instead of using Moment, I found a week-number algorithm on StackOverflow. If you want to use Moment's algo instead, go ahead.
The output data structure is not what you described.
Your example is not valid JSON, so I made a guess as to what you had in mind.
Here's an example of what it looks like:
{
"JUNE": {
"avgMonthTemp": 289.9727083333334,
"avgWeekTemps": {
"25": 289.99106382978727,
"26": 289.11
}
},
"JULY": {
"avgMonthTemp": 289.9727083333334,
"avgWeekTemps": {
"27": 289.99106382978727,
"30": 289.11
}
}
}
The output will include a top-level entry for every month, whether or not there is any data for that month. However, the avgWeekTemps hash will only have entries for weeks that are present in the data. Both behaviors can be changed, of course.
It's a reusable script that processes arbitrary JSON files in the format you shared.
You mentioned that each file has data from one city, so I figured you'll be running this on multiple files. I set it up so you can pass the path to the data file as a command-line argument. Note that the CLI logic is not sophisticated, so if you're doing funky things you will have a bad time. Doing CLI stuff well is a whole separate topic.
If your data for London is in a file named london.json, this is how you would process that file and save the results to the file london-temps.json:
$ node meantemp.js london.json > london-temps.json
// meantemp.js
const FS = require('fs')
// sets the language used for month names
// for language choices, see: http://www.iana.org/assignments/language-subtag-registry/language-subtag-registry
const MONTH_NAME_LANG_CODE = 'en-US'
// generate the list of month names once
const MONTH_NAMES = Array(12).fill().map(
( _, monthNum ) => new Date(2020, monthNum).toLocaleDateString(MONTH_NAME_LANG_CODE, { month: 'long' }).toUpperCase()
)
main()
function main() {
let filepath = process.argv[2]
let cityData = readJsonFile(filepath)
// before working on the data, prep the date values for processing
let allRows = cityData.map(row => {
let _date = new Date(row.dt_iso)
let _weekNum = getWeekNum(_date)
return { ...row, _date, _weekNum }
})
let output = MONTH_NAMES.reduce(( hash, monthName, monthNum ) => {
// grab this month's rows
let monthRows = getRowsForMonth(allRows, monthNum)
// calculate monthly average
let avgMonthTemp = getMeanTemp(monthRows)
// calculate weekly averages
let rowsByWeekNum = groupRowsByWeekNum(monthRows)
let avgWeekTemps = Object.keys(rowsByWeekNum)
.reduce(( hash, weekNum ) => ({
...hash,
[weekNum]: getMeanTemp(rowsByWeekNum[weekNum])
}), {})
return {
...hash,
[monthName]: { avgMonthTemp, avgWeekTemps }
}
}, {})
console.log(JSON.stringify(output))
}
function readJsonFile( path ) {
try {
let text = FS.readFileSync(path, 'utf8')
return JSON.parse(text)
} catch ( error ) {
if(error.code === 'ENOENT') {
console.error(`Could not find or read path ${JSON.stringify(path)}`)
process.exit()
} else if(error instanceof SyntaxError) {
console.error(`File is not valid JSON`)
process.exit()
} else {
throw error
}
}
}
function getRowsForMonth( rows, monthNum ) {
return rows.filter(row => monthNum === row._date.getUTCMonth())
}
function groupRowsByWeekNum( rows ) {
return rows.reduce(( hash, row ) => {
if(!hash.hasOwnProperty(row._weekNum)) {
hash[row._weekNum] = []
}
hash[row._weekNum].push(row)
return hash
}, {})
}
// ISO8601-compliant week-of-year function
// taken from https://stackoverflow.com/a/39502645/814463
// modified by me to prevent mutation of args
function getWeekNum( date ) {
// if date is a valid date, create a copy of it to prevent mutation
date = date instanceof Date
? new Date(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate())
: new Date()
let nDay = (date.getDay() + 6) % 7
date.setDate(date.getDate() - nDay + 3)
let n1stThursday = date.valueOf()
date.setMonth(0, 1)
if (date.getDay() !== 4) {
date.setMonth(0, 1 + ((4 - date.getDay()) + 7) % 7)
}
return 1 + Math.ceil((n1stThursday - date) / 604800000)
}
function getMeanTemp( hourlyReadings ) {
let temps = hourlyReadings.map(reading => reading.main.temp)
let mean = getMean(temps)
return mean
}
function getMean( numbers ) {
let sum = numbers.reduce(( sum, num ) => sum + num, 0)
let mean = sum / numbers.length
return mean
}
Ok,this is the first time I post on stackoverflow,so basically I am new to JS, React, Web Dev in general and I am having trouble making an array out of some data in the JSON response of an API.
I followed many similar tutorials for this but I can't seem to get it right, maybe I am making mistakes with the path.
This is some of the JSON:
meta: {code: 200}
response:
holidays: Array(34)
0:
date:
datetime: {year: 2019, month: 1, day: 1}
iso: "2019-01-01"
__proto__: Object
description: "New Year’s Day (Anul Nou) and the following day, on January 1 and 2 respectively, are annual holidays in Romania."
locations: "All"
name: "New Year's Day"
states: "All"
type: ["National holiday"]
__proto__: Object
1: {name: "Day after New Year's Day", description: "Both New Year’s Day (Anul Nou) and the following d…d 2 respectively, are annual holidays in Romania.", date: {…}, type: Array(1), locations: "All", …}
2: {name: "Unification Day", description: "Unification Day celebrates the political union bet…ch is deemed as the foundation of modern Romania.", date: {…}, type: Array(1), locations: "All", …}
This is how i tried to access the API with a componentDidMount:
componentDidMount() {
const endpoint = 'https://calendarific.com/api/v2/holidays?api_key=065cc39ad5c1967ae719985ce3850f264f0215b7015d801b098df1ca9fca725b&country=RO&year=2019';
fetch(endpoint)
.then(results => results.json())
}
And this is how I tried to make a function that takes the year month and day of all the elements in the array and returns another array with all the dates only:
holidayDateArray(data){
let holidayDates= data;
let holidays= holidayDates.response.holidays;
let holidaysArray= holidays.map((items, i)=>{
return {items.date.datetime.year}+" "+{items.date.datetime.month}+" "+{items.date.datetime.day}
});
}
Basically I want the holidayDateArray function to return an array made out of the dates of all the elements in the holidays array.
import React, {
Component
} from "react";
class MyComponent extends Component {
componentDidMount() {
const endpoint = 'https://calendarific.com/api/v2/holidays?api_key=065cc39ad5c1967ae719985ce3850f264f0215b7015d801b098df1ca9fca725b&country=RO&year=2019';
fetch(endpoint)
.then(response => response.json())
.then(myJson => {
const listOfDates = this.getListOfDates(myJson);
//set listOfDates to a state variable / instance variable and use as necessary
console.log(listOfDates);
});
}
getListOfDates(myJson) {
const holidayLists = myJson.response.holidays;
const dateList = holidayLists.map(holidayListItem => {
const dateTime = holidayListItem.date.datetime;
// return dateTime.iso;
return `${dateTime.year} ${dateTime.month} ${dateTime.day}`;
});
return dateList;
}
}
Try this one
fetch(endpoint)
.then(results => results.json()).then(r => console.log($.map(r.response.holidays, h => h.date)))
results.json() will return a promise,for when the deserialization is done, so you have to await it too. After that you can iterate over all elements in the array with $.map and return back an array based on the property date