I have a "format" array that's used in a map function to return an array of objects with start and end dates.
This format array contains the group of dates that belong to the same object.
let format = [3, 3, 1, 5, 4, 4, 3, 5, 13, 10, 3, 5, 5, 2, 2, 10];
So this way we know the first 3 dates same group, next 3 dates, same group, next date single group date, etc.
My issue/problem: is when there's a group of dates with no-lineal dates (for example 05, 06, 12, 13).
With my actual function, is returning an object with
Start: 05
End: 13
But this isn't correct, because we are counting all the days in the middle between 5 and 13. What I would like to do would create two objects for this case:
{
"start": 05,
"end": 06
},
{
"start": 12,
"end": 13
}
In my code, you can see this behavior with the last group of dates (10) (last object).
Is there any way to "check" for the range-dates" before creating the object? Should I add a .map inside the current .map to get 3 sets from the last 10
{
"2022-01-05T04:00:00.000Z", // start
"2022-01-06T04:00:00.000Z",
"2022-01-07T04:00:00.000Z" // end
},
{
"2022-01-10T04:00:00.000Z", // start
"2022-01-11T04:00:00.000Z",
"2022-01-12T04:00:00.000Z",
"2022-01-13T04:00:00.000Z",
"2022-01-14T04:00:00.000Z" // end
},
{
"2022-01-17T04:00:00.000Z", // start
"2022-01-18T04:00:00.000Z" // end
}
Current code:
let format = [3, 3, 1, 5, 4, 4, 3, 5, 13, 10, 3, 5, 5, 2, 2, 10];
let dates = [
"2021-10-04T04:00:00.000Z",
"2021-10-06T04:00:00.000Z",
"2021-10-07T04:00:00.000Z",
"2021-10-13T04:00:00.000Z",
"2021-10-14T04:00:00.000Z",
"2021-10-15T04:00:00.000Z",
"2021-10-15T04:00:00.000Z",
"2021-10-17T22:00:00.000Z",
"2021-10-18T22:00:00.000Z",
"2021-10-19T22:00:00.000Z",
"2021-10-20T22:00:00.000Z",
"2021-10-21T22:00:00.000Z",
"2021-10-17T22:00:00.000Z",
"2021-10-18T22:00:00.000Z",
"2021-10-19T22:00:00.000Z",
"2021-10-20T22:00:00.000Z",
"2021-10-19T04:00:00.000Z",
"2021-10-20T04:00:00.000Z",
"2021-10-21T04:00:00.000Z",
"2021-10-22T04:00:00.000Z",
"2021-10-19T04:00:00.000Z",
"2021-10-20T04:00:00.000Z",
"2021-10-21T04:00:00.000Z",
"2021-10-25T04:00:00.000Z",
"2021-10-26T04:00:00.000Z",
"2021-10-27T04:00:00.000Z",
"2021-10-28T04:00:00.000Z",
"2021-10-29T04:00:00.000Z",
"2021-10-25T04:00:00.000Z",
"2021-10-26T04:00:00.000Z",
"2021-10-27T04:00:00.000Z",
"2021-10-28T04:00:00.000Z",
"2021-10-29T04:00:00.000Z",
"2021-11-01T04:00:00.000Z",
"2021-11-02T04:00:00.000Z",
"2021-11-03T04:00:00.000Z",
"2021-11-04T04:00:00.000Z",
"2021-11-05T04:00:00.000Z",
"2021-11-08T04:00:00.000Z",
"2021-11-09T04:00:00.000Z",
"2021-11-10T04:00:00.000Z",
"2021-11-01T04:00:00.000Z",
"2021-11-02T04:00:00.000Z",
"2021-11-03T04:00:00.000Z",
"2021-11-04T04:00:00.000Z",
"2021-11-05T04:00:00.000Z",
"2021-11-08T04:00:00.000Z",
"2021-11-09T04:00:00.000Z",
"2021-11-10T04:00:00.000Z",
"2021-11-11T04:00:00.000Z",
"2021-11-12T04:00:00.000Z",
"2021-11-11T04:00:00.000Z",
"2021-11-12T04:00:00.000Z",
"2021-11-13T04:00:00.000Z",
"2021-11-15T04:00:00.000Z",
"2021-11-16T04:00:00.000Z",
"2021-11-17T04:00:00.000Z",
"2021-11-18T04:00:00.000Z",
"2021-11-19T04:00:00.000Z",
"2021-11-16T04:00:00.000Z",
"2021-11-17T04:00:00.000Z",
"2021-11-18T04:00:00.000Z",
"2021-11-19T04:00:00.000Z",
"2021-11-20T04:00:00.000Z",
"2021-11-23T04:00:00.000Z",
"2021-11-24T04:00:00.000Z",
"2021-11-23T04:00:00.000Z",
"2021-11-24T04:00:00.000Z",
"2022-01-05T04:00:00.000Z",
"2022-01-06T04:00:00.000Z",
"2022-01-07T04:00:00.000Z",
"2022-01-10T04:00:00.000Z",
"2022-01-11T04:00:00.000Z",
"2022-01-12T04:00:00.000Z",
"2022-01-13T04:00:00.000Z",
"2022-01-14T04:00:00.000Z",
"2022-01-17T04:00:00.000Z",
"2022-01-18T04:00:00.000Z"
];
const res = format.map(num => {
const arr = dates.splice(0,num)
const start = arr.shift();
const end = arr.length === 0 ? start : arr.pop()
return {
start: start,
end: end
}
})
console.log(res);
Related
I have the array like
[
"/core/api/v2.0/wallet/62da5521930eaf0f2e855": 1,
"/core/api/v2.0/wallet/62da382894c5dd0f9ab11": 1,
"/core/api/v2.0/users/sync/603a9c6a-c686-42af-b5f7-1f5bcfd75": 1,
"/core/api/v2.0/users/sync/64c73c5b-e6cc-4f98-9c54-69e7c796a": 3,
"/core/api/v2.0/users/sync/c3dfe00d-3950-401b-b068-d64aac99f39c": 3,
"/core/api/v2.0/users/sync/32cd70c8-ca92-4075-bb2f-1b9d99527723": 2,
"/core/api/v2.0/users/sync/245b0029-c05b-4007-bacb-656db21c170e": 1,
"/core/api/v2.0/users/sync/9175d6a9-386c-4b0d-9db4-c6053913c354": 1,
"/core/api/v2.0/tools/generate/trigger-download": 22,
"/core/api/v2.0/tools/generate/search-photos": 17,
]
I want the results like
[
"/core/api/v2.0/wallet/:id": 2,
"/core/api/v2.0/users/sync/:id: 11 "
"core/api/v2.0/tools/generate/:tool-name": 39,
]
just loop over array and keep counter if meets specific match likewise:
let wallet_match=0;
for (let i = 0; i < your_array.length; i++) {
if(your_array[i].includes("/core/api/v2.0/wallet/")) {
wallet_match+=1;
}
}
analogically you can list for other matches as well!
I built a simple NodeJS server that emits client events. An event is a JSON object that looks like this:
{
"date": "2019-12-12T09:55:05.679Z",
"clientId": "Client01",
"ip": "10.1.1.1",
"event": "someEvent"
}
An event can be emitted anytime. I get many messages with different timestamps (date).
Currently, I store all the data in memory.
How I can aggregate the client events by date?
let's say in 15-minute bulks, so I end up with a total number of client events for each time frame, for example:
const timestamps = ["2019-12-12T09:00:00.000Z", "2019-12-12T09:15:00.000Z", "2019-12-12T09:30:00.000Z"];
const totalNumEvents = [50, 27, 82];
const clientIds = ["Client01", "Client02", "Client03"];
Sorry if the question is too generic, I tried to look for direction by googling but couldn't find any solution without using a framework / DB like MongoDB.
So far, what I did is, creating an object for each clientId and push the event into it. (I have a callback for each event)
const onEventArrived = (client) => {
if (!clients[client.clientId]) {
console.log(`[New] Client Added - ${client.clientId}`);
clients[client.clientId] = [{ date, client}];
} else {
console.log(`[Exist] New Client Message for ${client.clientId}`);
clients[client.clientId].push({ date, client});
}
});
Back to question, I have all the events for each client, but how do I aggregate the random times into fixed 15 minute windows?
You will need to store the events as a flat object in an array and use Array.reduce() or lodash's groupBy() to group the array of event objects by any of the desired fields.
Here's an example using your supplied event example
Your incoming event looks like this:
{
"date": "2019-12-12T09:55:05.679Z",
"clientId": "Client01",
"ip": "10.1.1.1",
"event": "someEvent"
}
Now when this event is received, here's what happens:
const events = []
const onEventArrived = (event) => {
events = [...events, event ]
});
Next you run a group by as follows:
Array.prototype.groupBy = function(k) {
return this.reduce((acc, item) => ((acc[item[k]] = [...(acc[item[k]] || []), item]), acc),{});
};
events.groupBy("date")
// OR
events.groupBy("clientId")
You can extend this to fit your use case
Reference: How to group an array of objects by key
An idea can be to:
associate an id to each date (a quarterId)
get the minQuarterId, the maxQuarterId and fill those in between with 0
const bulks = {}
const clientIds = new Set
function onev(ev) {
clientIds.add(ev.clientId)
const quarters = ev.date.getTime() / (15 * 60 * 1000)
const quarterId = Math.floor(quarters)
bulks[quarterId] = (bulks[quarterId] || 0) + 1
}
function restitute() {
if(!Object.keys(bulks).length){ return { ts: [], nevs: [] } }
const ts = []
const nevs = []
const {min, max} = Object.keys(bulks).reduce((acc, k) => {
const pk = parseInt(k)
if(pk < acc.min){
acc.min = pk
}
if (pk > acc.max) {
acc.max = pk
}
return acc
}, {min:1e15, max:0})
for(let i = min; i <= max; ++i){
ts.push(new Date(i * 15 * 60 * 1000))
nevs.push(bulks[i] || 0) // fill with 0 if no quarterId "i" exists
}
return {ts, nevs}
}
onev({clientId: 1, date:new Date(2019, 11, 12, 13, 24)})
onev({clientId: 2, date:new Date(2019, 11, 12, 13, 28)})
onev({clientId: 1, date:new Date(2019, 11, 12, 13, 29, 30)})
onev({clientId: 1, date:new Date(2019, 11, 12, 13, 31, 30), newquarter:1})
onev({clientId: 4, date:new Date(2019, 11, 12, 13, 29, 30)})
onev({clientId: 4, date:new Date(2019, 11, 12, 12, 29, 30), emptyquarters:1})
onev({clientId: 4, date:new Date(2019, 11, 12, 12, 45, 30), indapast:1})
console.log(restitute())
const theme = createMuiTheme({
spacing: factor => [0, 4, 8, 16, 32, 64][factor],
});
theme.spacing(2); // = 8
This is a sample code in the Material-UI framework document.
Here is the original link to the code:https://material-ui.com/customization/spacing/
[factor] is not an array or a list, it's to get the element from the [0, 4, 8, 16, 32, 64] as an argument, like in this code
const theme = createMuiTheme({
spacing: factor => [0, 4, 8, 16, 32, 64][factor],
});
theme.spacing(2); // = 8
The spacing is function and the factor is parameter / argument
You only have one array in your code block. If you've used arrays before you should be familiar with how you can access indexes within the array to get particular elements:
// 0 1 2 2 3 4
const arr = [0, 4, 8, 16, 32, 64];
const eight = arr[2];
console.log(eight);
Above, I'm using bracket notation ([2]) which allows you to access a given element within the array. We can rewrite the above code to use the literal array [0, 4, 8, 16, 32, 41] in place of the arr variable like so:
const factor = 2; // make 2 a variable called `factor`
const eight = [0, 4, 8, 16, 32, 64][factor];
console.log(eight);
As you can see, [factor] is being used to get a particular value (using bracket notation) from the array [0, 4, 8, 16, 32, 64].
I have been trying to use a node.js script to turn some data into music. The script is only returning a single note for some reason:
The orignal script on github: https://github.com/wbkd/from-data-to-sound had res.concat(scribble.scale('c', but the threw an error Invalid Scale name.
const scribble = require('scribbletune');
// example data
const data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1];
const min = Math.min(...data);
const octaves = [...Array(5)].map((d, i) => i + 1); // [1, 2, 3, 4, 5]
// creates array of notes like 'c1', 'd1', 'e1', 'gb1', 'ab1', 'bb1', 'c2', ...
const notes = octaves.reduce((res, octave) =>
res.concat(scribble.scale('c1 major', 'whole tone', octave, false))
, []);
const midiData = scribble.clip({
notes: data.map(value => notes[value - min]),
pattern: 'x',
noteLength: '1/16',
});
// write the MIDI file 🎵🎵🎵
scribble.midi(midiData, 'data-sonification.mid');
From scribbletune doc:
each x implies a note on event
scribbletune docs/core/clip
Since you're passing only 1 'x' as a pattern in scribble.clip, it only plays 1 note. In order for all the notes to be played, you can try something like this:
const midiData = scribble.clip({
notes: data.map(value => notes[value - min]),
- pattern: 'x', // only play 1 note
+ pattern: 'x'.repeat(data.length), // repeat this pattern for each note in data
noteLength: '1/16',
});
I need to loop through an entire 2D array (OldTable) to check that Column1 has a value of 1 and Col7 is not empty (null). If the above conditions are true then push the current (i) arrays of elements into newTable.
My snippet of JS is as follow...
var newTable = [];
for (var i=1; i<OldTable.length; i++){
if(OldTable[i][0]==1 && OldTable[i][7]!==null){
newTable.push(OldTable[i]);
}
}
Seems like a fairly straight forward thing to do but currently hitting brick wall with this error...
TypeError: Cannot read property "0" from undefined. (line 80, file
"Code"
I have tried to reduce the if statement to just...
if(OldTable[i][0]==1){
...but still the same error.
I'm able to display the array element just fine using...
Browser.msgBox(OldTable[50][0]);
I'm fairly new to JS so could be a simple silly error someone could point out.
UPDATE: In trying to simplying naming, I've actually made it more difficult with conflicting terminology, so have going through and updated the variable names used.
Your code should work if, as noted in the comment by #Massimo, you change your loop from starting at i=1 to i=0, as shown below. Also, just to whet your appetite for more modern tools within JavaScript, I also include an essentially identical solution to the problem using ES6/ES2015.
var myArray = [
[1, 0, 0, 0, 0, 0, 0, 'foo' ], // should pass
[9, 1, 1, 1, 1, 1, 1, 'foo' ], // should fail
[1, 2, 2, 2, 2, 2, 2, 'foo' ], // should pass
[1, 3, 3, 3, 3, 3, 3, null ], // should fail
[0, 4, 4, 4, 4, 4, 4, null ], // should fail
[1, 5, 5, 5, 5, 5, 5, undefined], // should pass
[1, 6, 6, 6, 6, 6, 6, 'foo' ] // should pass
];
function f1(array) {
var newArray = [];
for (var i = 0; i < array.length; i++) {
if (array[i][0] == 1 && array[i][7] !== null) {
newArray.push(array[i]);
}
}
return newArray;
}
const f2 = array => array.filter(e => e[0] === 1 && e[7] !== null);
console.log(f1(myArray));
console.log(f2(myArray));