Related
I am working on LeetCode code challenge 480. Sliding Window Median:
You are given an integer array nums and an integer k. There is a sliding window of size k which is moving from the very left of the array to the very right. You can only see the k numbers in the window. Each time the sliding window moves right by one position.
Return the median array for each window in the original array. Answers within 10-5 of the actual value will be accepted.
I submitted my code, but it fails on test cases. I suspect that there is a problem in this part of my code:
const medianSlidingWindow = (array, window) => {
let start = 0;
let end = window - 1;
const min = new MinHeap(array);
const max = new MaxHeap(array);
const insert = (index) => {
if(max.size === 0){
max.push(index);
return;
}
(array[index] >= max.peak) ? min.push(index) : max.push(index);
balance();
}
const balance = () => {
if(Math.abs(max.size - min.size) >= 2){
const returned = (max.size > min.size) ? max.pop() : min.pop();
(max.size > min.size) ? min.push(returned) : max.push(returned);
}
}
const remove = (index) => {
(max.has(index)) ? max.pop(index, true) : min.pop(index, true);
balance();
}
const next = () => {
remove(start++);
insert(++end);
}
const getMedian = () => {
if(window % 2 === 0) return (max.peak + min.peak)/2;
return (max.size > min.size) ? max.peak : min.peak;
}
for(let i = 0; i <= end; i++){
insert(i);
}
const ret = [];
while(end < array.length){
ret.push(getMedian());
next();
}
return ret;
}
Here is the full code:
class MaxHeap{
#array = [];
#size = 0;
#reference = [];
#map = new Map();
constructor(reference = []){
this.#reference = reference;
}
get size(){
return this.#size;
}
/* Debug */
get array(){
return this.#array;
}
get peak(){
return this.get(0);
}
get(index){
if(index === null || index < 0 || index >= this.#array.length) return null;
return this.#reference[this.#array[index]];
}
has(indexReference){
return this.#map.has(indexReference);
}
swap(indexA, indexB){
let temp = this.#map.get(this.#array[indexA]);
this.#map.set(this.#array[indexA], indexB);
this.#map.set(this.#array[indexB], temp);
[this.#array[indexA], this.#array[indexB]] = [this.#array[indexB], this.#array[indexA]];
}
sink(index){
let currentIndex = index;
let greterChild;
while((this.get(greterChild = this.get(2*currentIndex+1) >= this.get(2*currentIndex + 2) ? 2*currentIndex + 1 : 2*currentIndex + 2) ?? Number.MIN_SAFE_INTEGER) > this.get(currentIndex)){
this.swap(currentIndex, greterChild);
currentIndex = greterChild;
}
}
bubble(index){
let currentIndex = index;
let parent;
while((this.get(parent = Math.ceil((currentIndex - 2)/2)) ?? Number.MAX_SAFE_INTEGER) < this.get(currentIndex)){
this.swap(currentIndex, parent);
currentIndex = parent;
}
}
push(...char){
if(char[0].constructor === Array) char = char.flat();
for(let i = 0; i < char.length; i++){
this.#array.push(char[i]);
this.#map.set(char[i], this.#array.length - 1)
this.bubble(this.#array.length - 1);
this.#size++;
}
}
pop(index = 0, fromReference = false){
const ret = (fromReference) ? index :this.#array[index];
if(fromReference) index = this.#map.get(index);
this.swap(index, this.#array.length - 1);
this.#map.delete(ret);
this.#array.pop();
this.sink(index);
this.#size--;
return ret;
}
}
class MinHeap extends MaxHeap{
constructor(reference = []){
super(reference);
}
get size(){
return super.size;
}
get peak(){
return super.peak;
}
/* Debug */
get array(){
return super.array;
}
bubble(index){
let currentIndex = index;
let parent;
while((this.get(parent = Math.ceil((currentIndex - 2)/2)) ?? Number.MIN_SAFE_INTEGER) > this.get(currentIndex)){
this.swap(currentIndex, parent);
currentIndex = parent;
}
}
sink(index){
let currentIndex = index;
let lesserChild;
while((this.get(lesserChild = this.get(2*currentIndex+1) >= this.get(2*currentIndex + 2) ? 2*currentIndex + 2 : 2*currentIndex + 1) ?? Number.MAX_SAFE_INTEGER) < this.get(currentIndex)){
this.swap(currentIndex, lesserChild);
currentIndex = lesserChild;
}
}
}
const medianSlidingWindow = (array, window) => {
let start = 0;
let end = window - 1;
const min = new MinHeap(array);
const max = new MaxHeap(array);
const insert = (index) => {
if(max.size === 0){
max.push(index);
return;
}
(array[index] >= max.peak) ? min.push(index) : max.push(index);
balance();
}
const balance = () => {
if(Math.abs(max.size - min.size) >= 2){
const returned = (max.size > min.size) ? max.pop() : min.pop();
(max.size > min.size) ? min.push(returned) : max.push(returned);
}
}
const remove = (index) => {
(max.has(index)) ? max.pop(index, true) : min.pop(index, true);
balance();
}
const next = () => {
remove(start++);
insert(++end);
}
const getMedian = () => {
if(window % 2 === 0) return (max.peak + min.peak)/2;
return (max.size > min.size) ? max.peak : min.peak;
}
for(let i = 0; i <= end; i++){
insert(i);
}
const ret = [];
while(end < array.length){
ret.push(getMedian());
next();
}
return ret;
}
What went wrong:
On the 30th testcase of the problem (link: https://leetcode.com/problems/sliding-window-median/submissions/859041571/), it resolves to a wrong answer but when I pick one of the windows that resolves to a wrong answer it gives me a correct answer. I'm currently confused because two of the heaps are fairly balanced (as one heap doesn't exceed above one element) and I've tested my heap that both seem to work perfectly. It will be very helpful if somebody helps me.
Link to SO questions I've followed:
How to implement a Median-heap
There are these problems in your heap implementation:
The get function will return null when an out of range index is given, which means the while condition in your sink method could sometimes choose an non-existing child (when there is only one child). Note that a numerical comparison with null will treat that null as 0, and depending of the sign of the value you compare it with can give false or true.
For example, your code fails this test case for that reason:
nums=[1,2,3,4]
k=4
You can fix this by returning undefined instead of null. Then also make sure that the false side of the comparison operator is the one with +1 (choosing the left child), while the true side takes the other child.
The pop method, when called with true for the second argument, does not guarantee to restore the heap property. It takes care of sinking the value at the given index, but does not consider the case where this value should actually bubble up!
For example, your code fails this test case for that reason:
nums=[10,6,5,2,3,0,8,1,4,12,7,13,11,9]
k=11
Here is a simplified example where I depict a min-heap with the referenced values:
5
/ \
8 6
/ \ /
10 12 7
If the node with value 10 is to be removed, the swap action will give this min-heap (which is correct):
5
/ \
8 6
/ \ /
7 12 10
And then your code calls sink on that node with value 7. It is clear that there is nothing to sink here, but instead that 7 should bubble up and swap with 8. Your code must foresee both scenarios: sift or bubble.
If you fix those two issues in your heap implementation, it will work.
I provide here the literal changes you have to make:
In the get method, replace return null with return undefined (or omit the explicit value)
In the MaxHeap sink method, swap the comparator expression, replacing:
while((this.get(greterChild = this.get(2*currentIndex+1) >= this.get(2*currentIndex + 2) ? 2*currentIndex + 1 : 2*currentIndex + 2) ?? Number.MIN_SAFE_INTEGER) > this.get(currentIndex)){
with:
while((this.get(greterChild = this.get(2*currentIndex+1) <= this.get(2*currentIndex + 2) ? 2*currentIndex + 2 : 2*currentIndex + 1) ?? Number.MIN_SAFE_INTEGER) > this.get(currentIndex)){
In the pop method, replace:
this.sink(index);
with:
this.sink(index);
this.bubble(index);
(You can also first check which of both is needed, but it doesn't hurt to just call both methods)
I have an Array of Log items, already sorted by their timestamp (number of milliseconds since 1970). Now I want to filter them by a specific time range, so I think of Binary Search, however this variant is different than all variants I knew before as I need to find a range within a range. Note that there may be none or multiple items at the value edges.
I came up with this to reduce one range requirement but still don't know how to get to the first/last edge items:
filterByTime(min: number, max: number): LogItem[] {
const items = this.items;
const len = items.length;
if (min === undefined && max === undefined) {
return items.slice(0, len - 1);
}
min = min || Number.MIN_VALUE;
max = max || Number.MAX_VALUE;
const fn = (a: LogItem) => {
if (a.time < min) {
return -1;
} else if (a.time > max) {
return 1;
} else {
return 0;
}
};
const lowerBound = this.binarySearchBound(fn, 0, len, true);
if (lowerBound == -1) { return []; }
const upperBound = this.binarySearchBound(fn, 0, len, false);
return items.slice(lowerBound, upperBound + 1);
}
binarySearchBound(compareFn: (a: LogItem) => number, left: number, right: number, isLowerBound: boolean): number {
const items = this.items;
if (items.length == 0) {
return -1;
}
if (isLowerBound && compareFn(items[0]) == 0) {
return 0;
} else if (!isLowerBound && compareFn(items[items.length - 1]) == 0) {
return items.length - 1;
}
while (left <= right) {
const mid = (left + right) / 2;
const item = this.items[mid];
const compare = compareFn(item);
if (compare < 0) {
left = mid + 1;
} else if (compare > 0) {
right = mid - 1;
} else {
// What to do now?
}
}
return -1;
}
Worst case scenario, I can just do a linear search from the edge since I can assume there are not that much items at the edge but surely there is a better way I didn't think of but then I may have to iterate through the whole result set if mid falls in the middle of the result set.
EDIT for adding a note: It's possible for min or max is undefined (and could be both, in which case I can just set an if and return the copy of the whole array). Is it better to just substitute it with MIN_VALUE and MAX_VALUE if they are undefined, or is there a better way to handle that case?
I would suggest the following:
Write two binary search functions, as the execution time is then not hampered by passing and checking the isLowerBound boolean.
Make the returned upperBound to mean the next index after the potential last index that belongs to the range. This corresponds with how arguments work with native functions like slice.
Don't use -1 as a special index. If coded well, an empty range will come out of the two binary searches any way and give an empty array as result
Make the compare function to work with 2 parameters, so you can actually search for either the min or the max value.
Yes, I would use MIN_VALUE and MAX_VALUE as defaults and not test for boundary cases. If boundary cases happen often, it might be worth to include those checks, but in general be aware that these checks will then be executed for every filter, which may bring down the average execution time.
Here is the suggested implementation with integer data (instead of objects) to keep it simple. In order to have it run in a snippet I also removed the type references:
function filterByTime(min=Number.MIN_VALUE, max=Number.MAX_VALUE) {
const fn = (a, b) => a - b; // simplified (should be a.time - b.time)
const lowerBound = this.binarySearchLowerBound(fn, 0, this.items.length, min);
const upperBound = this.binarySearchUpperBound(fn, lowerBound, this.items.length, max);
return this.items.slice(lowerBound, upperBound);
}
function binarySearchLowerBound(compareFn, left, right, target) {
while (left < right) {
const mid = (left + right) >> 1;
if (compareFn(this.items[mid], target) < 0) {
left = mid + 1;
} else { // Also when equal...
right = mid;
}
}
return left;
}
function binarySearchUpperBound(compareFn, left, right, target) {
while (left < right) {
const mid = (left + right) >> 1;
if (compareFn(this.items[mid], target) <= 0) { // Also when equal...
left = mid + 1;
} else {
right = mid;
}
}
return left;
}
// Demo with simplified data (instead of objects with time property)
this.items = [1, 2, 2, 2, 3, 4, 4, 5, 5, 5, 6, 7, 8, 8];
console.log(this.filterByTime(2, 4));
console.log(this.filterByTime(4, 5));
Combined the variants on this article, I merged first and last code into a single function:
filterByTime(items: LogItem[], min: number, max: number): LogItem[] {
const len = items.length;
if (len == 0) {
return [];
}
if (min === undefined && max === undefined) {
return items.slice(0, len - 1);
}
min = min || Number.MIN_VALUE;
max = max || Number.MAX_VALUE;
const fn = (a: LogItem) => {
if (a.time < min) {
return -1;
} else if (a.time > max) {
return 1;
} else {
return 0;
}
};
const lowerBound = this.binarySearchBound(fn, 0, len, true);
if (lowerBound == -1) { return []; }
const upperBound = this.binarySearchBound(fn, 0, len, false);
return items.slice(lowerBound, upperBound + 1);
}
binarySearchBound(compareFn: (a: LogItem) => number, left: number, right: number, isLowerBound: boolean): number {
const items = this.items;
if (items.length == 0) {
return -1;
}
if (isLowerBound && compareFn(items[0]) == 0) {
return 0;
} else if (!isLowerBound && compareFn(items[items.length - 1]) == 0) {
return items.length - 1;
}
let result = -1;
while (left <= right) {
const mid = (left + right) / 2;
const item = this.items[mid];
const compare = compareFn(item);
if (compare < 0) {
left = mid + 1;
} else if (compare > 0) {
right = mid - 1;
} else {
result = mid;
if (isLowerBound) {
right = mid - 1;
} else {
left = mid + 1;
}
}
}
return result;
}
I'm practicing recursion, and am trying to use it to constantly add individual digits in a number until there is only 1 digit left.
Basically, if the number is 84, it becomes 8+4 = 12 which then becomes 1 + 2 = 3.
Below is my attempt on it. Not sure what I'm missing..
const weirdSum = (num) => {
let result = 0;
const split = num.toString().split('');
if(split.length > 1){
for(let i=0;i<split.length;i++){
result = result + (split[i]*1);
}
weirdSum(result); // pass result as argument, which will be split.
}
return result; // return result if split.length is 1
}
there are 2 mistakes, one you need to return weirdSum(result);
another you are returning result which is 0 you should return num
const weirdSum = (num) => {
let result = 0;
const split = num.toString().split('');
if(split.length > 1){
for(let i=0;i<split.length;i++){
result = result + (split[i]*1);
}
return weirdSum(result); // pass result as argument, which will be split.
}
return num; // return result if split.length is 1
}
console.log(weirdSum(84));
let weirdSum = num => {
const split = num.toString().split('');
if(split.length > 1){
const sum = split.reduce((acc, it) => parseInt(it) + acc, 0)
return weirdSum(sum);
}
return num;
}
console.log(weirdSum(84));
console.log(weirdSum(123456));
const weirdSum = (num) => {
let result = 0;
const split = num.toString().split('');
if(split.length > 1){
for(let i=0;i<split.length;i++){
result = result + (split[i]*1);
}
return weirdSum(result); // pass result as argument, which will be split.
}
return split[0]; // return result if split.length is 1
}
console.log(weirdSum(84))
I just changed your codes to works properly, I have no idea it is optimized or not.
You need ti return the split[0] when recursion stack ends not the result!
This function isn't anonymous but it solves your problem
function weirdSum(num) {
if(parseInt(num/10) == 0) {
return num;
}
var num1 = 0;
while(num != 0) {
var d = parseInt(num%10);
num1=num1+d;
num=parseInt(num/10);
}
return weirdSum(num1);
}
How it works ?
Any single digit number when divided by 10 gives 0 as quotient ( parsing to int is required ), function exists when this condition is met ( the first if ).
In the while loop I'm extracting digits of the number ( starting from the last digit ), when we divide a number by 10, the remainder is always the same as the last digit, then we are adding this to the new num ( num1 ).
In the last step of the while loop, we are shortening the number by removing is last digit by dividing it by 10 and repacing the old num1 by quoatient.
const weirdSum = num => {
// figure out the sum
const sum = [...num + ""].reduce((a, e) => a + (e - 0), 0);
// recurse if necessary
return sum < 10 ? sum : weirdSum(sum);
}
console.log(weirdSum(84));
I am trying to get the total seconds from 2 timestamps. I am currently getting the total days, hours and minutes, but I am trying to get all the way to the second. I am unable to find the formula...
Can someone point me in the right direction of getting the seconds too, along with the days, hours and minutes that I have already accomplished.
Here is my code thus far:
//gets timestamps
var clockedIn = "2017-03-02 09:45:25";
var clockedOut = "2017-03-04 09:49:06";
//sets timestamps to vars
var now = clockedIn;
var then = clockedOut;
var diff = moment.duration(moment(then).diff(moment(now)));
//parses out times
var days = parseInt(diff.asDays());
var hours = parseInt(diff.asHours());
hours = (hours - days * 24);
var minutes = parseInt(diff.asMinutes());
minutes = minutes - (days * 24 * 60 + hours * 60);
//I am looking to get seconds here...
Any help would be appreciated, even if it is just a link.
Thanks
One simple solution is to create two Date objects and get the difference between them.
var clockedIn = new Date("2017-03-02 09:45:25");
var clockedOut = new Date("2017-03-04 09:49:06");
var seconds = (clockedOut-clockedIn)/1000
// divide by 1000 because the difference we get will be in milliseconds.
Do you mean this function? seconds()
There's a nice plugin for momentjs available on github that makes this kind of formating very nice, as you can simply specify a format for your duration. https://github.com/jsmreese/moment-duration-format
var clockedIn = "2017-03-02 09:45:25";
var clockedOut = "2017-03-04 09:49:06";
//sets timestamps to vars
var now = clockedIn;
var then = clockedOut;
var diff = moment.duration(moment(then).diff(moment(now)));
console.log(diff.format("d [days], H [hours], m [minutes] [and] s [seconds] "));
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.17.1/moment-with-locales.min.js"></script>
<script>
/*! Moment Duration Format v1.3.0
* https://github.com/jsmreese/moment-duration-format
* Date: 2014-07-15
*
* Duration format plugin function for the Moment.js library
* http://momentjs.com/
*
* Copyright 2014 John Madhavan-Reese
* Released under the MIT license
*/
(function (root, undefined) {
// repeatZero(qty)
// returns "0" repeated qty times
function repeatZero(qty) {
var result = "";
// exit early
// if qty is 0 or a negative number
// or doesn't coerce to an integer
qty = parseInt(qty, 10);
if (!qty || qty < 1) { return result; }
while (qty) {
result += "0";
qty -= 1;
}
return result;
}
// padZero(str, len [, isRight])
// pads a string with zeros up to a specified length
// will not pad a string if its length is aready
// greater than or equal to the specified length
// default output pads with zeros on the left
// set isRight to `true` to pad with zeros on the right
function padZero(str, len, isRight) {
if (str == null) { str = ""; }
str = "" + str;
return (isRight ? str : "") + repeatZero(len - str.length) + (isRight ? "" : str);
}
// isArray
function isArray(array) {
return Object.prototype.toString.call(array) === "[object Array]";
}
// isObject
function isObject(obj) {
return Object.prototype.toString.call(obj) === "[object Object]";
}
// findLast
function findLast(array, callback) {
var index = array.length;
while (index -= 1) {
if (callback(array[index])) { return array[index]; }
}
}
// find
function find(array, callback) {
var index = 0,
max = array.length,
match;
if (typeof callback !== "function") {
match = callback;
callback = function (item) {
return item === match;
};
}
while (index < max) {
if (callback(array[index])) { return array[index]; }
index += 1;
}
}
// each
function each(array, callback) {
var index = 0,
max = array.length;
if (!array || !max) { return; }
while (index < max) {
if (callback(array[index], index) === false) { return; }
index += 1;
}
}
// map
function map(array, callback) {
var index = 0,
max = array.length,
ret = [];
if (!array || !max) { return ret; }
while (index < max) {
ret[index] = callback(array[index], index);
index += 1;
}
return ret;
}
// pluck
function pluck(array, prop) {
return map(array, function (item) {
return item[prop];
});
}
// compact
function compact(array) {
var ret = [];
each(array, function (item) {
if (item) { ret.push(item); }
});
return ret;
}
// unique
function unique(array) {
var ret = [];
each(array, function (_a) {
if (!find(ret, _a)) { ret.push(_a); }
});
return ret;
}
// intersection
function intersection(a, b) {
var ret = [];
each(a, function (_a) {
each(b, function (_b) {
if (_a === _b) { ret.push(_a); }
});
});
return unique(ret);
}
// rest
function rest(array, callback) {
var ret = [];
each(array, function (item, index) {
if (!callback(item)) {
ret = array.slice(index);
return false;
}
});
return ret;
}
// initial
function initial(array, callback) {
var reversed = array.slice().reverse();
return rest(reversed, callback).reverse();
}
// extend
function extend(a, b) {
for (var key in b) {
if (b.hasOwnProperty(key)) { a[key] = b[key]; }
}
return a;
}
// define internal moment reference
var moment;
if (typeof require === "function") {
try { moment = require('moment'); }
catch (e) {}
}
if (!moment && root.moment) {
moment = root.moment;
}
if (!moment) {
throw "Moment Duration Format cannot find Moment.js";
}
// moment.duration.format([template] [, precision] [, settings])
moment.duration.fn.format = function () {
var tokenizer, tokens, types, typeMap, momentTypes, foundFirst, trimIndex,
args = [].slice.call(arguments),
settings = extend({}, this.format.defaults),
// keep a shadow copy of this moment for calculating remainders
remainder = moment.duration(this);
// add a reference to this duration object to the settings for use
// in a template function
settings.duration = this;
// parse arguments
each(args, function (arg) {
if (typeof arg === "string" || typeof arg === "function") {
settings.template = arg;
return;
}
if (typeof arg === "number") {
settings.precision = arg;
return;
}
if (isObject(arg)) {
extend(settings, arg);
}
});
// types
types = settings.types = (isArray(settings.types) ? settings.types : settings.types.split(" "));
// template
if (typeof settings.template === "function") {
settings.template = settings.template.apply(settings);
}
// tokenizer regexp
tokenizer = new RegExp(map(types, function (type) {
return settings[type].source;
}).join("|"), "g");
// token type map function
typeMap = function (token) {
return find(types, function (type) {
return settings[type].test(token);
});
};
// tokens array
tokens = map(settings.template.match(tokenizer), function (token, index) {
var type = typeMap(token),
length = token.length;
return {
index: index,
length: length,
// replace escaped tokens with the non-escaped token text
token: (type === "escape" ? token.replace(settings.escape, "$1") : token),
// ignore type on non-moment tokens
type: ((type === "escape" || type === "general") ? null : type)
// calculate base value for all moment tokens
//baseValue: ((type === "escape" || type === "general") ? null : this.as(type))
};
}, this);
// unique moment token types in the template (in order of descending magnitude)
momentTypes = intersection(types, unique(compact(pluck(tokens, "type"))));
// exit early if there are no momentTypes
if (!momentTypes.length) {
return pluck(tokens, "token").join("");
}
// calculate values for each token type in the template
each(momentTypes, function (momentType, index) {
var value, wholeValue, decimalValue, isLeast, isMost;
// calculate integer and decimal value portions
value = remainder.as(momentType);
wholeValue = (value > 0 ? Math.floor(value) : Math.ceil(value));
decimalValue = value - wholeValue;
// is this the least-significant moment token found?
isLeast = ((index + 1) === momentTypes.length);
// is this the most-significant moment token found?
isMost = (!index);
// update tokens array
// using this algorithm to not assume anything about
// the order or frequency of any tokens
each(tokens, function (token) {
if (token.type === momentType) {
extend(token, {
value: value,
wholeValue: wholeValue,
decimalValue: decimalValue,
isLeast: isLeast,
isMost: isMost
});
if (isMost) {
// note the length of the most-significant moment token:
// if it is greater than one and forceLength is not set, default forceLength to `true`
if (settings.forceLength == null && token.length > 1) {
settings.forceLength = true;
}
// rationale is this:
// if the template is "h:mm:ss" and the moment value is 5 minutes, the user-friendly output is "5:00", not "05:00"
// shouldn't pad the `minutes` token even though it has length of two
// if the template is "hh:mm:ss", the user clearly wanted everything padded so we should output "05:00"
// if the user wanted the full padded output, they can set `{ trim: false }` to get "00:05:00"
}
}
});
// update remainder
remainder.subtract(wholeValue, momentType);
});
// trim tokens array
if (settings.trim) {
tokens = (settings.trim === "left" ? rest : initial)(tokens, function (token) {
// return `true` if:
// the token is not the least moment token (don't trim the least moment token)
// the token is a moment token that does not have a value (don't trim moment tokens that have a whole value)
return !(token.isLeast || (token.type != null && token.wholeValue));
});
}
// build output
// the first moment token can have special handling
foundFirst = false;
// run the map in reverse order if trimming from the right
if (settings.trim === "right") {
tokens.reverse();
}
tokens = map(tokens, function (token) {
var val,
decVal;
if (!token.type) {
// if it is not a moment token, use the token as its own value
return token.token;
}
// apply negative precision formatting to the least-significant moment token
if (token.isLeast && (settings.precision < 0)) {
val = (Math.floor(token.wholeValue * Math.pow(10, settings.precision)) * Math.pow(10, -settings.precision)).toString();
} else {
val = token.wholeValue.toString();
}
// remove negative sign from the beginning
val = val.replace(/^\-/, "");
// apply token length formatting
// special handling for the first moment token that is not the most significant in a trimmed template
if (token.length > 1 && (foundFirst || token.isMost || settings.forceLength)) {
val = padZero(val, token.length);
}
// add decimal value if precision > 0
if (token.isLeast && (settings.precision > 0)) {
decVal = token.decimalValue.toString().replace(/^\-/, "").split(/\.|e\-/);
switch (decVal.length) {
case 1:
val += "." + padZero(decVal[0], settings.precision, true).slice(0, settings.precision);
break;
case 2:
val += "." + padZero(decVal[1], settings.precision, true).slice(0, settings.precision);
break;
case 3:
val += "." + padZero(repeatZero((+decVal[2]) - 1) + (decVal[0] || "0") + decVal[1], settings.precision, true).slice(0, settings.precision);
break;
default:
throw "Moment Duration Format: unable to parse token decimal value.";
}
}
// add a negative sign if the value is negative and token is most significant
if (token.isMost && token.value < 0) {
val = "-" + val;
}
foundFirst = true;
return val;
});
// undo the reverse if trimming from the right
if (settings.trim === "right") {
tokens.reverse();
}
return tokens.join("");
};
moment.duration.fn.format.defaults = {
// token definitions
escape: /\[(.+?)\]/,
years: /[Yy]+/,
months: /M+/,
weeks: /[Ww]+/,
days: /[Dd]+/,
hours: /[Hh]+/,
minutes: /m+/,
seconds: /s+/,
milliseconds: /S+/,
general: /.+?/,
// token type names
// in order of descending magnitude
// can be a space-separated token name list or an array of token names
types: "escape years months weeks days hours minutes seconds milliseconds general",
// format options
// trim
// "left" - template tokens are trimmed from the left until the first moment token that has a value >= 1
// "right" - template tokens are trimmed from the right until the first moment token that has a value >= 1
// (the final moment token is not trimmed, regardless of value)
// `false` - template tokens are not trimmed
trim: "left",
// precision
// number of decimal digits to include after (to the right of) the decimal point (positive integer)
// or the number of digits to truncate to 0 before (to the left of) the decimal point (negative integer)
precision: 0,
// force first moment token with a value to render at full length even when template is trimmed and first moment token has length of 1
forceLength: null,
// template used to format duration
// may be a function or a string
// template functions are executed with the `this` binding of the settings object
// so that template strings may be dynamically generated based on the duration object
// (accessible via `this.duration`)
// or any of the other settings
template: function () {
var types = this.types,
dur = this.duration,
lastType = findLast(types, function (type) {
return dur._data[type];
});
// default template strings for each duration dimension type
switch (lastType) {
case "seconds":
return "h:mm:ss";
case "minutes":
return "d[d] h:mm";
case "hours":
return "d[d] h[h]";
case "days":
return "M[m] d[d]";
case "weeks":
return "y[y] w[w]";
case "months":
return "y[y] M[m]";
case "years":
return "y[y]";
default:
return "y[y] M[m] d[d] h:mm:ss";
}
}
};
})(this);
</script>
You don't have to use any complex method to calculate the difference of the two moment (or Date) objects. Simply calculating the difference gives you the total difference between the two dates in milliseconds.
var now = moment();
var then = moment().add(1231, 'second'); // just to have an example different date
var milliseconds = +then - +now;
var seconds = milliseconds / 1000;
var minutes = seconds / 60;
var hours = minutes / 60;
If you would like to get the difference formatted like HH:mm:ss, just convert the diff milliseconds back to moment object and use .format():
var now = moment();
var then = moment().add(1231, 'second'); // just to have an example different date
var diff_m = moment(+then - +now);
console.log(diff_m.format('HH:mm:ss'));
I have an array as
arr = [1,2,3,4,6,7,8,9]
Now I want to check if the values in the array are consecutive.
Being more specific, I want this
First Check gives first and second element are consecutive and the next element is not consecutive then the algo must return the first element from where the consecutive number started
Like
First Check will give 1
Second Check will give 6
and so on...
Please help
Thanks in advance
/**
* Given an array of number, group algebraic sequences with d=1
* [1,2,5,4,8,11,14,13,12] => [[1,2],[4,5],[8],[11,12,13,14]]
*/
import {reduce, last} from 'lodash/fp';
export const groupSequences = (array) => (
reduce((result, value, index, collection) => {
if (value - collection[index - 1] === 1) {
const group = last(result);
group.push(value);
} else {
result.push([value]);
}
return result;
}, [])(array)
);
/**
* Given an array of number, group algebraic sequences with d=1
* [1,2,3,4,5,6] => true
* [1,2,4,5,6] => false
*/
const differenceAry = arr.slice(1).map(function(n, i) { return n - arr[i]; })
const isDifference= differenceAry.every(value => value == 1)
console.log(isDifference);
One sidenote is that you want to call it multiple times, so each call should know which array it's working on and what the previous offset in that array was. One thing you can do is to extend the native Array object. [Demo]
Array.prototype.nextCons = (function () {
var offset = 0; // remember the last offset
return function () {
var start = offset, len = this.length;
for (var i = start + 1; i < len; i++) {
if (this[i] !== this[i-1] + 1) {
break;
}
}
offset = i;
return this[start];
};
})();
Usage
var arr = [1,2,3,4,6,8,9];
arr.nextCons(); // 1
arr.nextCons(); // 6
arr.nextCons(); // 8
Check if all numbers in array are consecutives:
Updated March 2022
const allConsecutives = (arr) =>{
if(arr.some(n=> typeof n !== "number" || Number.isNaN(n))) return false;
return arr.every((num, i)=> arr[i+1]-num === 1 || arr[i+1] === undefined)
}
pseudo code:
int count = 0
for i = 0 to array.length - 2
if {array[i + 1] - array[i] = 1 then
count+=1
return i
else count=0}
const array1 = [1,2,3];
const sum = array1.reduce((accumulator, currentValue) =>{
return accumulator + currentValue;
});
const max = Math.max(...array1);
maximum = max
if(sum == maximum * (maximum+1) /2) {
console.log(true);
} else {
console.log(false);
}