How to find all objects where time difference between each consecutive object is less than 1 minute.
const input = [
{ id: 12,
time: '2018-03-01T12:34:00.000Z'},
{ id: 15,
time: '2018-03-02T09:25:20.000Z'},
{ id: 19,
time: '2018-03-04T07:14:20.000Z'},
{ id: 23,
time: '2018-04-01T10:24:00.000Z'},
{ id: 24,
time: '2018-04-01T10:24:40.000Z'},
{ id: 25,
time: '2018-04-01T10:25:10.000Z'}
]
expected output ===> [
{ id: 23,
time: '2018-04-01T10:24:00.000Z' },
{ id: 24,
time: '2018-04-01T10:24:40.000Z' },
{ id: 25,
time: '2018-04-01T10:25:10.000Z' }
]```
Assuming that there's only exactly one run of consecutive items in one minute, you can use the following algorithm:
Ensure your list is sorted, which in this case it seems is already in ascending time order, so I'll skip this step. You should not skip this step is the list isn't guaranteed to be sorted.
We want to find the first two consecutive items. Loop through each element of the array, starting from the second. For each item:
Check the difference in time between the previous item and the current one. If it is less than a minute, the previous and current items are the first consecutive entries. Stop the loop (break).
If we have iterated through the whole array without finding any consecutive entries, return an empty list.
We now want to find the rest of the consecutive items. Loop through each item starting from the item directly after the last known consecutive item. For each item:
If the time difference between the previous and current items is more than a minute, stop the loop (break).
Otherwise, the current item is also consecutive. Count it in, and continue the loop.
Return all known consecutive items.
Here is one such implementation:
// `entries` is of type `{ id: number; time: string; }`
function getConsecutiveEntries(entries) {
// Find the first two consecutive entries
let idx;
for (idx = 1; idx < entries.length; idx++) {
const prevTime = new Date(entries[idx - 1].time).getTime();
const curTime = new Date(entries[idx].time).getTime();
if (curTime - prevTime <= 60000) break;
}
if (idx === entries.length) return [];
const result = [entries[idx - 1], entries[idx]];
// Find the rest of consecutive entries
idx++;
while (idx < entries.length) {
const prevTime = new Date(entries[idx - 1].time).getTime();
const curTime = new Date(entries[idx].time).getTime();
if (curTime - prevTime > 60000) break;
result.push(entries[idx]);
idx++;
}
return result;
}
This implementation can be further optimized by memoizing the the results of Date to number conversions (the new Date(...).getTime()) calls, which happens twice for most entries.
Related
So on LeetCode, I need to return the sum of two numbers that equal the target number. This is a leetcode "easy" type. I've never done leetcode before so I decided to give it a try. Right off the bat, I was able to solve the problem but my solution was nonsenical because it checks each number in the array against eachother. So if the input is a million digits then it will check it a million times for each number.
It's worth noting that although my program works, it can be submitted due to time limit exceeding.
I'm not sure what the mathematical solution would be to opitmize this. I'm currently going to Maths again learning what I am weak at.
Code:
var twoSum = function(nums, target) {
let total = [];
let inc = 1;
let intVal = 0;
let startingPos = nums[intVal];
let nextPos = nums[inc];
for(let x = 0; x < nums.length; x++){
// Do not check the value of position 1 with position 2
if(nums.indexOf(startingPos) === nums.lastIndexOf(nextPos)){
nextPos++;
}
if(startingPos + nextPos === target){
console.log(`First Value ${startingPos}`)
console.log(`Second Value ${nextPos}`)
console.log(`Target ${target}`)
// A match has been found
return [nums.indexOf(startingPos), nums.lastIndexOf(nextPos)];
} else{
// Move to next number if index 1 is not eql
// nextPos++;
let nextPosIndex = nums[inc];
nextPos = nums[inc];
console.log(`Values [${startingPos}], [${nextPos}]`)
console.log("No Matches");
// Increment the next value to check
inc++;
// Reset loop if no match is found from 2nd position
if(x == (nums.length - 1)){
// Increment the initial value in first pos
intVal++;
startingPos = nums[intVal];
// Reset values to check new numbers
x = 0;
inc = 1;
}
// check if we exhausted all options
if(startingPos === undefined){
return "No Matches.";
}
}
}
};
twoSum([5, 2, 5, 5, 1, 3, 6, 8, 4, 3, 2, 7], 14)
--
Before proceeding to any more problems, I am afraid I will be in this loop of choosing the most illogical way of solving the problems.
What can I do to modify this problem to quickly check if two values equals the target.
Here is a live compiler example: https://replit.com/#FPpl/SafeHeartfeltArchitect#index.js
When iterating over a number, you can put the value that, if it would match to sum to the target, into a collection (with O(1) lookup). For example, if you iterate over a number 5, and the target is 20, put 15 into the collection.
During an iteration, if the number being iterated over already exists in the collection, you have a match from one you found previously, and you can return both indicies.
const twoSum = function(nums, target) {
// For this Map, the key is the number which, if found again, is a match
// eg, if target is 20, and the number 5 is iterated over
// the key will be 15
// The value is the index of the prior number found - eg, index of 5
const valuesAlreadyFound = new Map();
for (let i = 0; i < nums.length; i++) {
const num = nums[i];
if (valuesAlreadyFound.has(num)) {
// We have a match, get both indicies:
console.log('Match for values', target - num, num);
return [valuesAlreadyFound.get(num), i];
}
// This wasn't a match. Identify the number which, when paired, is a match
const matchNeeded = target - num;
valuesAlreadyFound.set(matchNeeded, i);
}
return 'No match';
};
console.log('Indicies found:', twoSum([5, 2, 5, 5, 1, 3, 6, 8, 4, 3, 2, 7], 14));
I have a problem optimizing the runtime for my code. Ideally, what I'm trying to achieve is that all the operations below is performed in a single loop, so that I don't have to run through the dataset many times as I'm doing now (very large dataset!)
The code is transforming aggData to an array on the following format: [0: 0, 1: 0, 2: 0, 3: 43, 4: 121, 5: 0, ....], where each number represents a year in the interval, if the interval is (1800-2020) 0 will represent the count for 1800, 1 will be 1801 and so on ..
aggData is an array of objects on the following format: {key_as_string: "1900-01-01T00:00:00.000Z", key: -2208988800000, doc_count: 17}. The start-year is the first year with a doc_count higher than 0.
Below I provide a description of what each step does as the code is now:
Here I am changing the format of each object in the list to be : {year: number, count: number}
const formatAggData = aggData
.map((item: AggData) => {
return { year: moment(item.key_as_string).year(), count: item.doc_count };
});
This function creates an array of objects with the from as start year and to as end year, if the year already exists in existingArray it uses the count from there, if not it sets count to 0.
function fillYears(from: number, to: number, existingArray: YearCount[]) {
const existingObject: { [year: string]: number } = { year: null };
existingArray.map((x: YearCount) => (existingObject[x.year] = x.count));
const yearsArray = [];
for (let i = from; i <= to; i++) {
yearsArray.push({
year: i,
count: existingObject[i] || 0,
});
}
return yearsArray;
}
Converts year values to count-values, where the first year in the list will be 0 with the corresponding value, second will be 1 with corresponding value and so on..
const resultList = fillYears(min, max, formatAggData).map(
(item: YearCount) => item.count,
);
I was looking at you code. can't you do it like this? it looks like you don't need to know the year at this moment
function fillYears(from: number, to:number, existingYears: YearCount[]) {
for (let i = from; i <= to; i++) {
yearsArray.push({
year: i,
count: existingYears[i].doc_count || 0,
});
}
}
I am building a booking app. I have created an object with times and the number of vacancies for each of these times.
{
1000: 1,
1030: 4,
1100: 4,
1130: 2,
1200: 0,
1230: 1,
1300: 0
//...
}
Times are separated in 30 minute intervals, but services can take longer than 30 minutes (but are all multiples of 30 themselves). E.g.: service1.duration = 90
I now need to build a script that identifies in which periods of time a service can be executed. In the example above, 90/30 = 3, so I would have to find 3 sequential keys in that object that have a value > 0.
There would be two in the example above: [1000, 1030, 1100] and [1030, 1100, 1130].
Ideally, the periods would be returned in an array just as the two I have exemplified.
Problem: I don't know how to iterate over both keys and values. I know Object.keys and Object.values can be used, but not how to combine them.
You can use both Object.keys and Object.values together, as they are both guaranteed to be in ascending order for number-like keys.
const times = {
1000: 1,
1030: 4,
1100: 4,
1130: 2,
1200: 0,
1230: 1,
1300: 0
//...
};
const getPeriods = time => {
const keys = Object.keys(times);
const values = Object.values(times);
const res = [];
for(let i = 0; i <= values.length - time; i++){
let works = true;
for(let j = i; j < i + time && works; j++){
if(values[j] <= 0){
works = false;
}
}
if(works){
res.push(keys.slice(i, i + time));
}
}
return res;
};
console.log(getPeriods(3));
I have some good experience in programming but I am new to Javascript. I ran into an unexpected result with a comparison in an if function.
In the function below there is a double comparison in the if.function. The first comparison is expected to return a false when .name is already in the list. But one of the tests returns a set where a weekday occurs twice.
In the debugger, the comparison ls.name != MPopArray[0].name returns true basically saying "Saturday"!="Saturday" is TRUE. So my question how does it get to this result?
function mostPopularDays(week) {
week.sort(function (a,b) {return b.traffic-a.traffic})
var highestTraffic = week[0].traffic
var MPopArray = []
MPopArray[0] = week[0].name
for (const ls of week) {
if ((ls.name != MPopArray[0].name) && (ls.traffic==highestTraffic)) {
MPopArray.push(ls.name)
}
}
return MPopArray
}
The function iterates through week and determines which day of the week had the highest traffic. If more than one day of the week has the same traffic, the day is appended to the list.(ex. ["Wednesday", "Thursday"]). The first condition in the
Test Dataset
var Test1MPD = [
{ name: 'Thursday', traffic: 100 },
{ name: 'Friday', traffic: 100 },
{ name: 'Saturday', traffic: 101 }
];
var Test1ResultMPD = mostPopularDays(Test1MPD)
console.log(Test1MPD)
console.log(Test1ResultMPD)
On the test dataset that I am using I am expecting ls.name != MPopArray[0].name to return a false condition.
Result returned by function
["Saturday", "Saturday"]
You could sort the array, take an index for comparing traffic of following items and push the actual name to the result set.
function mostPopularDays(week) {
var index = 0,
result = [];
week.sort((a, b) => b.traffic - a.traffic);
while (index < week.length && week[0].traffic === week[index].traffic) {
result.push(week[index++].name);
}
return result;
}
var test1MPD = [{ name: 'Thursday', traffic: 100 }, { name: 'Friday', traffic: 100 }, { name: 'Saturday', traffic: 101 }];
console.log(mostPopularDays(test1MPD));
I have a variable that looks like this:
var objList = [{variantId: "1111", quantity: 2},
{variantId: "222222", quantity: 2},
{variantId: "333333", quantity: 2},
{variantId: "44444", quantity: 1}]
I am looking to write a function that takes in a number between 1 and all of the quantities added together ( in this example 7 ) then it will contstruct a new variable that has a total quantity of the input
Items will be added in this order:
variantId:1111 - add one of these to the new variable
variantId:2222 - add one of these ""
variantId:3333 - add on of these ""
variantID:4444 - add the only one of these
variantID:1111 - add the second one of these to new variable
variantID:2222 - add the second one of these ""
variantID:3333 - add the second one of these ""
the function will look something like this.
function(x){
var newObj = [];
var i=0;
while(i<x){
//logic to add the necessary item from the objList
// really struggling here
i++;
}
return newObj;
}
Iterate the array while you still have space in your inventory
Check that the current item still has quantity
If it doesn't, skip it
If it does, decrement the item's quantity and add that item to inventory
Return the inventory
Consider this code:
const objList = [{
variantId: "1111",
quantity: 1
},
{
variantId: "222222",
quantity: 2
},
{
variantId: "333333",
quantity: 2
},
{
variantId: "44444",
quantity: 1
}
];
function distribute(list, count) {
// Track our distributed items
const ret = [];
// Clone and reverse the array input the array for good measure
let clone = list
.map(item => Object.assign({}, item))
.reverse();
// Start idx at the "begining"
let idx = clone.length - 1;
// Iterate through the inventory while we have room and items
while (count-- && clone.length) {
// Push the current item
ret.push(clone[idx].variantId);
// Decrement the quantity of items
clone[idx].quantity--;
// If we are out of the item, remove it
if (!clone[idx].quantity) {
clone.splice(idx, 1);
}
// Go to the next item
idx--;
// If we reach the "end" of the inventory
if (!idx) {
// Go back to the "begining"
idx = clone.length - 1;
}
}
// Return our parceled items
return ret;
}
// Test it
console.log(distribute(objList, 5))