I would like to compute a remain-to-do count per month, in foundry-function, from an objects-set having topicOpenTs and topicCloseTs properties (Both Timestamp type). Remain-to-do is a simple difference inflow value - outflow value for each month cumulated month after month (thank to stackoverflow topic 72883635).
I'm blocked because both aggregations don't have the same buckets : Inflow has 126 buckets (aka months) and outflow has 123 buckets (aka months).
A JS wait to proceed could be to create an object where Key is the key object of inflow and outflow aggregations and Value is the difference of inflow/outflow values for this month or 0 if it doesn't exist.
But TypeSCript complexify my way because I not used to manipulate strict Types and I get errors again and again. I tried during 5 hours and my code below is just too poor... I'm humbly asking for help.
My try lead me to this code but it doesn't work:
export class MyFunctions {
#Function()
public async cumulativeTopicsByMonth(topics: ObjectSet<MeFalWbTcardsTopics>): Promise<TwoDimensionalAggregation<IRange<Timestamp>, Double>> {
const bucketedInflow = await topics
.groupBy(topic => topic.topicOpenTs.byMonth())
.count();
//outflow
const bucketedOutflow = await topics
.groupBy(topic => topic.topicCloseTs.byMonth())
.count();
//************and what I would like to do but that doesn't work:
const allKeys = Array.from(new Set([...bucketedInflow.buckets.map(b => b.key), ...bucketedOutflow.buckets.map(b => b.key)]))
const allBuckets = allKeys.map(key => {
let inflow = bucketedInflow.buckets.find(inBucket => inBucket.key == key)
let outflow = bucketedOutflow.buckets.find(outBucket => outBucket.key == key)
return {key, value: inflow-outflow}
}
const remainToDo = {buckets: allBuckets}
********//end of the durty part with lot of Type Errors
//final steps similaire to [stackoverflow topic 72883635]
const sortedBucketedRtd = sortBuckets(remainToDo );
const cumulativeSortedBucketedRtd = cumulativeSum2D(sortedBucketedRtd );
return cumulativeSortedBucketedRtd
return {buckets: allBuckets}
}
Related
The "Make a Person" intermediate algorithm scripting challenge on freeCodeCamp requires you to fill an object constructor with the following methods:
/*
getFirstName()
getLastName()
getFullName()
setFirstName(first)
setLastName(last)
setFullName(firstAndLast)
*/
My code is as follows and includes the test cases and their required values commented in at the end:
const Person = function(firstAndLast) {
// Only change code below this line
// Complete the method below and implement the others similarly
//create a holder variable to hold a copy of the full name passed as parameter
let fullName = firstAndLast;
//create a variable to pay respect to "DRY" so as not to have to type this variable and method multiple times throughout
let splitter = fullName.split(" ");
//return the first name from the full name passed as parameter
this.getFirstName = function() {
return splitter[0];
};
//return the last name from the full name passed as parameter
this.getLastName = function() {
return splitter[1];
};
//return the full name passed as a parameter
this.getFullName = function() {
return fullName;
};
//update the full name to now include the given first name instead of the original passed parameter
this.setFirstName = function(first) {
fullName = first + " " + splitter[1];
};
//update the full name to now include the given last name instead of the original passed parameter
this.setLastName = function(last) {
fullName = splitter[0] + " " + last;
};
//update the full name to the given firstAndLast name instead of the original passed parameter
this.setFullName = function(newFull) {
fullName = newFull;
};
};
//create a new Person, bob, and name him 'Bob Ross'
const bob = new Person('Bob Ross');
//expected to return => 'Bob Ross'
let result = bob.getFullName();
//no expected return value, but fullName should now return => 'Haskell Curry'
bob.setFullName('Haskell Curry')
//my code here returns => 'Haskell Curry'
let result2 = bob.getFullName();
//my code here returns => 'Bob'
//should be returning => 'Haskell'
let result3 = bob.getFirstName();
//my code here returns => 'Ross'
//should be returning => 'Curry'
let result4 = bob.getLastName();
//Console.log in place for value testing during algorithm creation
console.log(result, result2, result3, result4)
//Check for length of bob, should not exceed 6 for the purposes of this test
console.log(Object.keys(bob).length)
/*Tests
Required returning values for each test
bob instanceof Person => true (Passing)
Object.keys(bob).length => 6 (Passing)
bob.firstName => undefined (Passing)
bob.lastName => undefined (Passing)
bob.getFirstName() => "Bob" (Passing)
bob.getLastName() => "Ross" (Passing)
bob.getFullName() => "Bob Ross" (Passing)
bob.getFullName() => "Haskell Ross" AFTER bob.setFirstName("Haskell") (Passing)
bob.getFullName() => "Haskell Curry" AFTER bob.setLastName("Curry") (Passing)
bob.getFullName() => "Haskell Curry" AFTER bob.setFullName("Haskell Curry") (Passing)
bob.getFirstName() => "Haskell" AFTER bob.setFullName("Haskell Curry") (NOT Passing)
bob.getLastName() => "Curry" AFTER bob.setFullName("Haskell Curry") (NOT Passing)
*/
After checking my code up against the solution code, the two are virtually the same, the only differences are the usage of
let splitter = fullName.split(" ")
//this does not exist in the solution code
//used in my code to avoid having to type fullName.split(" ") multiple times throughout
And where the setters ask for parameters "first", "last", and "newFull", respectively, the solution code uses "name" for each instead
I couldn't imagine that these two differences could make that big of a difference, so could I get some clarity in the understanding of their importance, and furthermore, why my code won't pass all the cases as is? Thanks in advance!
let arr = [1,2,3,4,5,6,7,8];
let a = arr.filter( data => {
return data > 5;
}).map ( (data,index) => {
// while in here -- is there away to know that only 3 elements came out of the filter?
});
Yes, I know I can wait for the a.length when this is over, but while IN the map -- can I find out how many items made it through the filter?
The map method's callback accepts a third argument that gives you the array being mapped, you can use the length property on that.
let arr = [1,2,3,4,5,6,7,8];
let a = arr.filter( data => {
return data > 5;
}).map ( (data,index,arr) => {
console.log(arr.length);
});
Instructions
Create a web interface that allows a user:
To filter a list of players based on specific criteria. These are the search filters you will be creating based on the test data:
Age: allow the user to filter for players within a specific age or age range (e.g. 7, 5-9, 15-17, etc.)
Gender: allow the user to filter for players based on their specified gender
State: allow the user to filter for players based on the state they reside in from available test data
Status: allow the user to filter for players based on their status (active/inactive)
You can apply more than one filter to narrow down your search results.
To edit the information of any player.
CODE
I'm trying to use React Hooks, just wanting a few points of clarity on what I'm doing.
1) I'm wondering if my initial state for each variable makes sense. Also, on the useEffect method, that just needs to be run once to fetch the data with axios and that's all that is needed correct?
2) Just need 4 separate functions that handle each criteria. Would I just need to map through the array of objects and filter the wanted results?
import React, { useEffect, useState } from 'react';
import axios from 'axios';
const App = () => {
const url = "https://dii-test.s3.amazonaws.com/players.json";
const [age, setAge] = useState([]);
const [gender, setGender] = useState([]);
const [state, setState] = useState('');
const [status, setStatus] = useState(false);
useEffect(() => {
axios.get(url).then(json => setAge(json.data))
}, []);
const renderTable = () => {
return age.map(user => {
return (
<tr>
<td>{user.age}</td>
</tr>
)
})
}
return (
<div className="App">
<tbody>{renderTable()}</tbody>
</div>
);
}
export default App;
I'd have a single state object for the players and then another (or multiple) to keep track of the filters. Something like:
const [genderFilter, setGenderFilter] = useState(null)
const [players, setPlayers] = useState([])
Then you can filter them in one fell swoop - either a series of tests inside a filter of the players array, or in a series of filters if you find chaining more readable and performant:
return (
<table>
<tbody>
{players.map(player => {
// After all the filters are run, map the players to table rows
return (
<tr>
<td>{player.name}</td>
<td>{player.age}</td>
<td>{player.state}</td>
<td>{player.gender}</td>
<td>{player.status}</td>
</tr>
)
}).filter(player => {
// genderFilter can be "male", "female", or null
return genderFilter ? player.gender === genderFilter : true
}).filter(player => {
// ageFilter is an object with min & max
return player.age >= ageFilter.min && player.age <= ageFilter.max
}).filter(player => {
// stateFilter can be a string or null
return stateFilter ? player.state == stateFilter : true
}).filter(player => {
// statusFilter can be "active" or "inactive"
return statusFilter === player.status
})}
</tbody>
</table>
)
That's the quick, dirty, and ugly version just to show the logic. It obviously doesn't include any displays/messages if the filters end up removing all players, waiting/loading message for the user during the axios call, etc.
And this is also only for a small to medium sized data set - if you have to download and filter thousands of results on the client side, it will be slow and your user would be better served sending the data to the server to query and return just the appropriate results.
I've a data structure like this (generated by normalizr):
const data = fromJS({
templates: {
"83E51B08-5F55-4FA2-A2A0-99744AE7AAD3":
{"uuid": "83E51B08-5F55-4FA2-A2A0-99744AE7AAD3", test: "bla"},
"F16FB07B-EF7C-440C-9C21-F331FCA93439":
{"uuid": "F16FB07B-EF7C-440C-9C21-F331FCA93439", test: "bla"}
}
})
Now I try to figure out how to replace the UUIDs in both the key and the value of the template entries. Basically how can I archive the following output:
const data = fromJS({
templates: {
"DBB0B4B0-565A-4066-88D3-3284803E0FD2":
{"uuid": "DBB0B4B0-565A-4066-88D3-3284803E0FD2", test: "bla"},
"D44FA349-048E-4006-A545-DBF49B1FA5AF":
{"uuid": "D44FA349-048E-4006-A545-DBF49B1FA5AF", test: "bla"}
}
})
A good candidate seems to me the .mapEntries() method, but I'm struggling on how to use it ...
// this don't work ... :-(
const result = data.mapEntries((k, v) => {
const newUUID = uuid.v4()
return (newUUID, v.set('uuid', newUUID))
})
Maybe someone can give me a hand here?
mapEntries is the correct method. From the documentation, the mapping function has the following signature:
mapper: (entry: [K, V], index: number, iter: this) => [KM, VM]
This means that the first argument is the entry passed in as an array of [key, value]. Similarly, the return value of the mapper function should be an array of the new key and the new value. So your mapper function needs to look like this:
([k, v]) => {
const newUUID = uuid.v4()
return [newUUID, v.set('uuid', newUUID)]
}
This is equivalent to the following (more explicit) function:
(entry) => {
const key = entry[0]; // note that key isn't actually used, so this isn't necessary
const value = entry[1];
const newUUID = uuid.v4()
return [newUUID, value.set('uuid', newUUID)]
}
One thing to note is that the templates are nested under the templates property, so you can't map data directly -- instead you'll want to use the update function.
data.update('templates', templates => template.mapEntries(...)))
So putting everything together, your solution should look like the following:
const result = data.update('templates', templates =>
templates.mapEntries(([k, v]) => {
const newUUID = uuid.v4()
return [newUUID, v.set('uuid', newUUID)]
})
);
Consider this scenario:
app loads => fetches json from api => needs to modify json returned
In this case, I'm using moment to make some date modifications and do some grouping that I'll use in the UI. I looked on stack and found a similar question but didn't feel like it provided the clarity I am seeking.
Where should I use .map to create the new objects that contain the formatted & grouped dates? Should I manipulate the raw json in the api call or in the redux action before I dispatch? What is the best practice?
Is it OK to add properties and mutate the object as I am showing below,
service["mStartDate"] = mStartDate before I put the data into my store and treat it as immutable state?
First Approach - changing raw json in the api call
class TicketRepository extends BaseRepository {
getDataByID(postData) {
return this.post('api/lookup', postData)
.then(result => {
const groupedData = {}
return result.map(ticket => {
const mStartDate = moment(ticket.startDate)
const mEndDate = moment(ticket.endDate)
const serviceLength = mStartDate.diff(mEndDate,'hours')
const duration = moment.duration(serviceLength,"hours").humanize()
const weekOfYear = mStartDate.format('WW')
const dayOfWeek = mStartDate.format("d")
if(!groupedData.hasOwnProperty(weekOfYear)){
groupedData[weekOfYear] = {}
}
if (!groupedData[weekOfYear].hasOwnProperty(dayOfWeek)) {
groupedData[weekOfYear][dayOfWeek] = []
}
service["mStartDate"] = mStartDate
service["mEndDate"] = mEndDate
service["serviceLength"] = serviceLength
service["duration"] = duration
groupedData[weekOfYear][dayOfWeek].push(service)
})
})
}
}
2nd Approach, make a simple api call
class TicketRepository extends BaseRepository {
getDataByID(postData) {
return this.post('api/lookup', postData)
}
}
Change the json in the action before dispatching
export function getDataByID() {
return (dispatch, getState) => {
dispatch(dataLookupRequest())
const state = getState()
const groupedData = {}
return TicketRepository.getDataByID(userData)
.then(result => {
const groupedData = {}
return result.map(ticket => {
const mStartDate = moment(ticket.startDate)
const mEndDate = moment(ticket.endDate)
const serviceLength = mStartDate.diff(mEndDate,'hours')
const duration = moment.duration(serviceLength,"hours").humanize()
const weekOfYear = mStartDate.format('WW')
const dayOfWeek = mStartDate.format("d")
if(!groupedData.hasOwnProperty(weekOfYear)){
groupedData[weekOfYear] = {}
}
if (!groupedData[weekOfYear].hasOwnProperty(dayOfWeek)) {
groupedData[weekOfYear][dayOfWeek] = []
}
service["mStartDate"] = mStartDate
service["mEndDate"] = mEndDate
service["serviceLength"] = serviceLength
service["duration"] = duration
groupedData[weekOfYear][dayOfWeek].push(service)
})
return groupedData
})
.then(groupedData => {
dispatch(lookupSuccess(groupedData))
})
.catch(err => dispatch(dataLookupFailure(err.code, err.message)))
}
}
All data manipulation should be handled by your reducer. That is, the returned response data should be passed on to a reducer. This practice is common, because this way if there's a problem with your data, you will always know where to look - reducer. So neither of your approaches is "correct". Actions should just take some input and dispatch an object (no data manipulation).
When you want to manipulate data for 'view' purposes only, consider using reselect library, which makes it easier to handle "data views" that are composed of the existing data.