I have an array of time ranges with start & end values.
var timeRanges = [{
start: 120,
end: 140
},{
start: 180,
end: 220
},{
start: 250,
end: 300
}]
Need to check whether the selected range overlap the time range or not. And also the selected range should be in between the timeRange intervals. (Ex: 140-180, 220-250)
var selected = {
start: 150,
end: 170
}
Time interval B 'overlaps' A if:
B starts after A starts but before A finishes.
B starts before A starts and finishes after A starts.
So you can write a function which decides exactly that.
function areOverlapping(A, B) {
if(B.start < A.start) {
return B.finish > A.start;
}
else {
return B.start < A.finish;
}
}
const overlaps = timeRanges.some( range =>
(range.start < selected.start && range.end > selected.start) ||
(range.start < selected.end && range.end > selected.end) ||
(range.start > selected.start && range.end < selected.end)
);
Assuming that your time ranges are sorted, this solution will work. Otherwise, you need to implement time range sorting as well.
function isValidRange(timeRanges, selectedRange) {
var isValid = true;
var minStart = timeRanges[0].start;
var maxEnd = timeRanges[timeRanges.length - 1].end;
if(selectedRange.start < selectedRange.end && selectedRange.start > minStart && selectedRange.end < maxEnd) {
for(var i=0; i<timeRanges.length; i++) {
if((selectedRange.start >= timeRanges[i].start && selectedRange.start <= timeRanges[i].end)
|| (selectedRange.end >= timeRanges[i].start && selectedRange.end <= timeRanges[i].end)) {
isValid = false;
break;
}
else if(i != timeRanges.length - 1) {
if(selectedRange.start > timeRanges[i].end && selectedRange.start < timeRanges[i+1].start) {
if(selectedRange.end < timeRanges[i+1].start) {
break;
}
else {
isValid = false;
break;
}
}
}
}
}
else {
isValid = false;
}
return isValid;
}
var timeRanges = [{
start: 120,
end: 140
},{
start: 180,
end: 220
},{
start: 250,
end: 300
}];
var selected = {
start: 141,
end: 222
};
alert(isValidRange(timeRanges, selected));
Why don't you run your selection through the array and calculate what you need?
timeRanges.forEach(function(aRange, index)) {
if (selected.start > aRange.start && selected.end < aRange.end)
console.log('Selection falls within the item ' + index):
}
Related
You are given an array (which will have a length of at least 3, but could be very large) containing integers. The array is either entirely comprised of odd integers or entirely comprised of even integers except for a single integer N. Write a method that takes the array as an argument and returns this "outlier" N
Example: [2, 4, 0, 100, 4, 11, 2602, 36]
Should return: 11 (the only odd number)
my sol:
function findOutlier(integers){
var odd = false;
var even = false;
if ((integers[0]%2===0) && (integers[1]%2===0)) || ((integers[1]%2===0) && (integers[2]%2===0)){
even = true;
}else{
odd = true;
}
if (odd){
for (var i = 0; i < integers.length; i++){
if (integers[i]%2 === 0){
return integers[i];
}}
}else if (even){
for (var i = 0; i < integers.length; i++){
if (integers[i]%2 !== 0){
return integers[i];
}}
}
}
Your first if-condition needs to be surrounded by parenthesis:
if a || b needs to be if (a || b). Then it works. :)
function findOutlier(integers) {
var odd = false;
var even = false;
if (((integers[0] % 2 === 0) && (integers[1] % 2 === 0)) || ((integers[1] % 2 === 0) && (integers[2] % 2 === 0))) {
even = true;
} else {
odd = true;
}
if (odd) {
for (var i = 0; i < integers.length; i++) {
if (integers[i] % 2 === 0) {
return integers[i];
}
}
} else if (even) {
for (var i = 0; i < integers.length; i++) {
if (integers[i] % 2 !== 0) {
return integers[i];
}
}
}
}
var result = findOutlier([2, 4, 0, 100, 4, 11, 2602, 36] );
console.log(result);
Here's another approach to solve that:
function findOutlier(integers) {
var outlier;
var odd = [];
var even = [];
// Push odd numbers to odd array and even numbers to even array.
integers.forEach(function(element) {
if (element % 2 == 0) even.push(element);
else odd.push(element);
});
// Ensure that the input is valid.
if (odd.length != 1 && even.length != 1) {
console.log("There is no single outlier! The array contains " + odd.length + " odd integers and " + even.length + " even integers.")
} else {
// Get outlier.
outlier = (odd.length == 1 ? odd[0] : even[0]);
}
return outlier;
}
var result = findOutlier([2, 4, 0, 100, 4, 11, 2602, 36]);
console.log(result);
I'm working on a project where I process large chunks of data. In my Javascript I receive this data via Ajax as an array of objects.
An example of this data is:
{ageatdeath: 0, death_count: 4, death_percent: 66.66666666666667}
For every age (ranging from 0 - ~100) I have an object. What I'm trying to do is group those together in ranges of 10 years (e.g. 0-10, 11-20) and create a Pie chart with plotly.
I'm able to do this, but I use a lot of almost duplicate code to achieve this. I'm wondering if there's a 'better' way to achieve this.
Here's my code for the function I'm using now.
function drawPieChartAgeAtDeath(data) {
var range0_10 = null;
var range11_20 = null;
var range21_30 = null;
var range31_40 = null;
var range41_50 = null;
var range51_60 = null;
var range61_70 = null;
var range71_80 = null;
var range81_90 = null;
var range90plus = null;
for (var i = 0, len = data.length; i < len; i++) {
if (data[i].ageatdeath >= 0 && data[i].ageatdeath <= 10) {
range0_10 += data[i].death_percent;
} else if (data[i].ageatdeath >= 11 && data[i].ageatdeath <= 20) {
range11_20 += data[i].death_percent;
} else if (data[i].ageatdeath >= 21 && data[i].ageatdeath <= 30) {
range21_30 += data[i].death_percent;
} else if (data[i].ageatdeath >= 31 && data[i].ageatdeath <= 40) {
range31_40 += data[i].death_percent;
} else if (data[i].ageatdeath >= 41 && data[i].ageatdeath <= 50) {
range41_50 += data[i].death_percent;
} else if (data[i].ageatdeath >= 51 && data[i].ageatdeath <= 60) {
range51_60 += data[i].death_percent;
} else if (data[i].ageatdeath >= 61 && data[i].ageatdeath <= 70) {
range61_70 += data[i].death_percent;
} else if (data[i].ageatdeath >= 71 && data[i].ageatdeath <= 80) {
range71_80 += data[i].death_percent;
} else if (data[i].ageatdeath >= 81 && data[i].ageatdeath <= 90) {
range81_90 += data[i].death_percent;
} else if (data[i].ageatdeath >= 91) {
range90plus += data[i].death_percent;
}
}
var pie_data = [{
values: [range0_10,
range11_20,
range21_30,
range31_40,
range41_50,
range51_60,
range61_70,
range71_80,
range81_90,
range90plus],
labels: ['0-10 year',
'11-20 year',
'21-30 year',
'31-40 year',
'41-50 year',
'51-60 year',
'61-70 year',
'71-80 year',
'81-90 year',
'> 90 year'],
type: 'pie'
}];
var layout = {
height: 400,
width: 500
};
Plotly.newPlot('pieChartDiv', pie_data, layout);
Any help would be really appreciated!
Dividing the age by 10, and flooring it will group things into the buckets you desire. You'll need to offset by 1 as groupings go from 0-10, then 11-20, (as opposed to 0-9, 10-19). Below will automatically generate new buckets greater than 10 if ages exceed 100. Buckets may be empty if there is no data for the age range.
function drawPieChartAgeAtDeath(data) {
var values = [];
for (var i = 0, len = data.length; i < len; i++) {
let valueBucket = Math.floor(Math.max(data[i].ageatdeath-1,0)/10);
values[valueBucket] = values[valueBucket] || 0;
values[valueBucket] += data[i].death_percent;
}
var pie_data = [{
values: values,
labels: ['0-10 year',
'11-20 year',
'21-30 year',
'31-40 year',
'41-50 year',
'51-60 year',
'61-70 year',
'71-80 year',
'81-90 year',
'> 90 year'],
type: 'pie'
}];
var layout = {
height: 400,
width: 500
};
Plotly.newPlot('pieChartDiv', pie_data, layout);
}
You can generate the ranges much more elegantly like this:
const ranges = Array.from({ length: 10 }, () => 0);
data.forEach(item => {
const initRangeIndex = Math.floor((item.ageatdeath - 1) / 10);
const rangeIndex = initRangeIndex === -1 ? 0 :
initRangeIndex > 9 ? 9
: initRangeIndex;
ranges[rangeIndex] += item.death_percent;
});
const pieData = [{
values: ranges,
// ...
I'm trying to write a function that returns an array of equally chunked up dates and number of days pertaining to those dates. Should there be a remainder of those days they get appended to the array as follow.
Expected outcome:
[{
'startDate' : 20160719 //dates generated from momentjs
'numOfDays': 5
},{
'startDate' : 20160724
'numOfDays': 5
},{
'startDate' : 20160729
'numOfDays': 3
}]
Below is the function I've written in which you can pass in a start date (momentjs), the total number of days (daysToDisplay) and number of days to be divided by (numOfDays).
function buildQueue(startDate, numOfDays, daysToDisplay) {
if (!startDate || !numOfDays || !daysToDisplay) {
throw new Error('All params required!');
}
var num = numOfDays > daysToDisplay ? daysToDisplay : numOfDays;
var div = Math.floor(daysToDisplay / num);
var count = daysToDisplay;
var rem = daysToDisplay % num;
var lastItem;
var i;
var arr = [];
for (i = 0; i <= daysToDisplay; i += num) {
arr.push({
startDate: moment(startDate, 'YYYYMMDD').add(i, 'days').format('YYYYMMDD'),
numOfDays: numOfDays,
count: i
})
if (rem === count) {
break;
}
count -= num;
}
if (count > 0) {
lastItem = arr[arr.length - 1];
var leftover = daysToDisplay - lastItem.count;
arr.push({
startDate: moment(lastItem.startDate, 'YYYYMMDD').add(num, 'days').format('YYYYMMDD'),
numOfDays: rem,
count: leftover + lastItem.count
});
}
return arr;
}
A working example is here (https://jsfiddle.net/zv5ghqpa/1/). The code appears to work in scenarios where daysToDisplay is dividable by more than 2.
When daysToDisplay is only dividable by one, we get an additional item in the returned array basically due to the zero index in the for loop. The expected outcome if I call buildQueue('20160719', 5, 8) should be:
[{
'startDate': 20160719
'numOfDays': 5
}, {
'startDate': 20160724
'numOfDays': 3
}]
Instead its returning:
[{
'startDate': 20160719
'numOfDays': 5
},{
'startDate': 20160724
'numOfDays': 5
}, {
'startDate': 20160729
'numOfDays': 3
}]
I hope i've given enough info... this is really doing my head in.
Thanks in advance!
I think this is code you're looking for:
function buildQueue(startDate, numOfDays, daysToDisplay) {
if (!startDate || !numOfDays || !daysToDisplay) {
throw new Error('All params required!');
}
var num = numOfDays > daysToDisplay ? daysToDisplay : numOfDays;
var div = Math.floor(daysToDisplay / num);
var count = daysToDisplay;
var rem = daysToDisplay % num;
var n = 0;
var i;
var arr = [];
for (i = 0; i <= daysToDisplay; i += num) {
arr.push({
startDate: moment(startDate, 'YYYYMMDD').add(i, 'days').format('YYYYMMDD'),
numOfDays: daysToDisplay % num,
count: i
})
console.log(rem + ' ' + count);
if (rem === count) {
count = 0;
break;
}
count -= num;
}
if (count > 0) {
var leftover = daysToDisplay - arr[arr.length - 1].count;
arr.push({
startDate: moment(arr[arr.length - 1].startDate, 'YYYYMMDD').add(num, 'days').format('YYYYMMDD'),
numOfDays: daysToDisplay % num,
count: leftover + arr[arr.length - 1].count
});
}
return arr;
}
//console.log(buildQueue(moment(), 80, 100));
console.log(buildQueue(moment(), 5, 8));
//console.log(buildQueue(moment(), 15, 100));
//console.log(buildQueue(moment(), 30, 100));
//console.log(buildQueue(moment(), 45, 100));
I think the 'Expected outcome' was correct before you edited the question. I also note the sample code produced a count property that you don't want in the output.
Perhaps this code does what you want?
function buildQueue(startDate, numOfDays, daysToDisplay) {
var arr = []
while (daysToDisplay > 0) {
arr.push({
startDate: moment(startDate, 'YYYYMMDD')
.add(numOfDays * arr.length, 'days')
.format('YYYYMMDD'),
numDays: Math.min(numOfDays, daysToDisplay)
})
daysToDisplay -= numOfDays
}
return arr
}
I am trying to check the week object's minutes and hours and I cannot figure out what I am doing wrong. The week object can contain variations of Day1 - Day7 so I dont want to check them specifically. I want to check the nested Hours/Minutes. I also don't want to use jquery and it has to work with ie8. Any help would be greatly appreciated.
week = {
Day1: {
Hours: 6,
Minutes: 20
},
Day2: {
Minutes: 45
},
Day3: {
Hours: 8,
Minutes: 15
}
};
hoursInValid = false;
minutesInValid = false;
for (var item in week) {
if (week.hasOwnProperty(item)) {
for (var i = 0; i < week[item].length; i++ )
{
if (week[item][i].Hours > 6) {
hoursInValid = true;
break;
}
if (week[item][i].Minutes > 20) {
minutesInValid = true;
break;
}
}
}
}
I don't see the need for the internal for loop. This is the solution I came up with. I added checks to make sure the DayN objects have Hours and Minutes properties.
week = {
Day1: {
Hours: 6,
Minutes: 20
},
Day2: {
Minutes: 45
},
Day3: {
Hours: 8,
Minutes: 15
}
};
hoursInValid = false;
minutesInValid = false;
for (var item in week) {
if (week[item].hasOwnProperty('Hours')) {
if (week[item].Hours > 6) {
hoursInValid = true;
break;
}
}
if (week[item].hasOwnProperty('Minutes')) {
if (week[item].Minutes > 20) {
minutesInValid = true;
break;
}
}
}
Try this:
for (var day in week) {
for (var unit in week[day]) {
if (unit === 'Hours' && week[day][unit] > 6) {
hoursInvalid = true;
} else if (unit === 'Minutes' && week[day][unit] > 20) {
minutesInvalid = true;
}
}
}
The break statements may not allow you to iterate over all the properties.
Do this instead:
var invalidHours = {}, invalidMinutes = {};
for(var i in week){
var w = week[i];
if(w.hasOwnProperty('Hours')){
invalidHours[i] = w.Hours > 6 ? true : false;
}
else{
// no hours
}
if(w.hasOwnProperty('Minutes')){
invalidMinutes[i] = w.Minutes > 20 ? true : false;
}
else{
// no minutes
}
}
if(invalidHours.Day1) // day 1 hours are invalid
if(invalidMinutes.Day2) // day 2 minutes are invalid
Assume i have a function checkTime like the one below where i have to check for multiple condition simultaneously.
var result=0;
function checkTime(time1, time2) {
if (time1 >= 0 && time2 <= 0) {
result = 1;
}
else if (time1 >= 0 && time2 <= 1) {
result = 4;
}
else if (time1 >= 2 && time2 <= 3) {
result = 5;
}
else if (time1 >= 4 && time2 <= 6) {
result = 6;
}
else if (time1 >= 7 && time2 <= 9) {
result = 7;
}
else if (time1 >= 11 && time2 <= 12) {
result = 8;
}
else if (time1 >= 13 && time2 <= 15) {
result = 9;
}
else if (time1 >= 16 && time2 <= 17) {
result = 10;
}
else if (time1 >= 19 && time2 <= 20) {
result = 11;
}
return result;
}
(The above given example is hypothetical)
The function i have used totally works,but:
Is there a better method or procedure or formula to replace this?(where it doesnt have to be this lengthy or ugly)
Thanx!
You can use an array to represent all the combination:
tests = [
{ time1: 0, time2: 0, result: 1 },
{ time1: 0: time2: 1, result: 4 },
...
];
for (var i = 0; i < tests.length; i++) {
if (time1 >= tests[i].time1 && time2 <= tests[i].time2) {
return tests[i].result;
}
}
If the code is identical, and only the values change, you could do something like this:
function checkTime(time1, time2) {
[
[0, 0, 0],
[0, 1, 0]
].forEach(function (it) {
if (time1 >= it[0] && time2 <= it[1]) {
return it[2];
}
});
}
Well, first off you have the possibility of an undefined result, so that makes things ambiguous. Should result start at 0 instead? This is an important detail. Second, you seem to be working with boundaries, so it would help to change the <= to < to make this clearer. (If so, the 7-9/11-12 section has a bug.) Third, you have an implicit comparison of time1 and time2, so make that explicit.
var result = 0;
var diff = time2 - time1;
var bounds = [21, 19, 16, 13, 11, 7, 4, 2, 0];
if (diff <= 0) result = 0; // unexpected outcome
else
for (position = 1; position < bounds.length; ++position) {
if (time1 >= bounds[position]) {
if (time2 < bounds[position - 1]) {
result = 3 + (bounds.size - position);
}
break;
}
}
return result;
Other implementations are possible, but it's hard to tell based on your question exactly what problem you're solving.
follow-up
This section of code has a gap:
else if (time1 >= 7 && time2 <= 9) {
result = 7;
}
else if (time1 >= 11 && time2 <= 12) {
result = 8;
}
If time = 10 and time2 = 10, there is no match. It's easy to miss this type of error when you are repeating yourself. Specifying lower and upper bounds for each condition is unnecessary repetition. Since I couldn't see a pattern to the bounds (which could be delegated to a function), I just put the lower bounds into an array and made sure it was sorted descending so that the loop could stop after the first match.