I have a table with 52 rows that represent 52 weeks.
a user can fill in a start week and a end week (ex: start: 5 end: 15) also a user can fill in how many product he was to add and if needed a interval (ex: 3 products skip 5 weeks 3 product again skip 5 weeks etc…)
i am really stuck on the last part and i know dont know how to achieve it.
Hi thank you very much for taking time to answer.
It should be the other way arround now it skips 5 and adds 2 but it needs to add 2 then skip 5 add 2 then skip 5 stc… ofcourse depending on wha the user fills in.
And it adds 2 in 1 week but what i need is 1 in 2 weeks and then skip 5 weeks.
Example: 1,1,0,0,0,0,0,1,1,0,0,0,0,0,1,1,0,0,0,0,0 etc…
Is there a way to reverse the modulus function ?
Hi Pullo, this is exacly what i want. Thank youre very much for taking time to answer my question.
Im very new to javascript and i still dont understand what you did but it works.
Paul thank you very much for this clean example and it did the job aswell.
i got 1 last question bacause i want to learn from this. could you explain what you did and how it works. i want to understand it and not just copy paste
That’s not right. We want order.end to take precendence, not the value with order.add added to it. The easy way to achieve that is to take the smaller of the two.
Which reveals another issue. The last week number in this test should be 21, but it’s not showing. This can be achieved only if j is checked to be less than or equal to the value of weekEnd.
Wow, that’s really wrong, but it’s easy to see why. It’s counting 3 additions now instead of the expected 2. Adding the “or equal to” part means that order.add is counting one too many. Starting at 5 we currently have an end of 5+2. When using “or equal to” we want that instead to just be 5+1 instead.
Removing one from order.add is what we need for good correct behaviour, and adding brackets around it helps to inform us what it’s for.
No other testing shows further improvements that are reasonably required, so it’s good to go.
Putting it all together we end up with:
var order = {start: 1, end: 20, add: 2, step: 2},
i, weekEnd;
for (i = order.start; i <= order.end; i += (order.add + order.step)) {
weekEnd = Math.min(i + (order.add - 1), order.end);
for (j = i; j <= weekEnd; j += 1) {
console.log(j);
}
}
Other things can be done to improve it, such as extracting out well named functions for each loop, and using more expressive techniques instead of just for loops, but that can be extra for later
As an example, here is a complete rewrite using more modern techniques, that can also help to make the code easier to understand.
The Array.from() method is new one in ES6 that lets us create an array of values, which can be used so that we can create rangedArray(5) which gives us [0, 1, 2, 3, 4]
An inclusive range will also give us just the values that we need, for a which a small function can help to encapsulate the details.
function rangeSizeInclusive(start, end) {
// Being inclusive, we also count the start and end values.
// As an example, the range from 1 to 10 is 10.
return end - start + 1;
}
var rangeSize = rangeSizeInclusive(order.start, order.end);
return Array.from(new Array(rangeSize), offsetFromStart);
// [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]
Now we can put this in to a rangedArray function which allows us to create a full array of weeks from the start to the end, in a more expressive manner:
From there, we can use the values of add and step to filter the weeks further.
With an add of 2 and a step of 2, we have a total period of 4. We want to allow the first two in the add section, and remove the ones in the step area.
With modulus arithmetic on the array index using the total period, we can get 0,1,2,3,0,1,2,3, …
By keeping the ones that are less than the add value, we end up successfully excluding the ones we want to step over.
var fullPeriod = order.add + order.step;
weeks = weeks.filter(function (week, i) {
// For each modulus period 0f 0,1,2,3,...,0,1,2,3,... we
// only want to keep those that are in the add section.
if (i % fullPeriod < order.add) {
return true;
}
});
We can further simplify things by pulling i % fullPeriod and the conditional check out into separate sections:
var periodOfWeek = i % fullPeriod;
function isAllowedPeriod(period, limit) {
return period < limit;
}
return isAllowedPeriod(period, order.add);
We could keep working on this but I think that you get the main idea, of extracting out complexity so that the code is easier to understand and maintain.
The full working code after performing more tidy-ups is as follows: bear in mind that it also needs the Array.from() polyfill too.
The resulting code is longer, but is more expressive and easier to modify and understand.
// Filter weeks based on a regular occurance
// Properties: start, end, add, step
// example usage:
// var weeks = filteredWeeks({start: 1, end: 20, add: 2, step: 2});
// Resulting array: [1, 2, 5, 6, 9, 10, 13, 14, 17, 18]
var filteredWeeks = function (order) {
function offsetFromStart(value, i) {
return order.start + i;
}
function rangedArray(size, arrayValueHandler) {
return Array.from(new Array(size), arrayValueHandler);
}
function rangeSizeInclusive(start, end) {
// An inclusive range includes the start and end numbers.
// As an example, the range from 5 to 10 is 6.
return end - start + 1;
}
function isAllowedPeriod(period, limit) {
return period < limit;
}
function filterByAddStepPeriod(week, i) {
// For each modulus period of 0,1,2,3,...,0,1,2,3,... we only
// want to keep those that are limited to the add section.
var fullPeriod = order.add + order.step,
periodOfWeek = i % fullPeriod;
return isAllowedPeriod(periodOfWeek, order.add);
}
var rangeSize = rangeSizeInclusive(order.start, order.end),
weeks = rangedArray(rangeSize, offsetFromStart);
return weeks.filter(filterByAddStepPeriod);
};
var weeks = filteredWeeks({start: 1, end: 20, add: 2, step: 2});
alert('The filtered weeks are: ' + weeks);