Ways to simplify an array of objects that is repeated several times - javascript

I wonder if I can simplify and use less lines of code for this purpose:
I have a class called "worker", and that class has a method that reads the properties (name, age, etc...) from a series of simple arrays.
Until there, everything is fine. Now, one of the properties that I want to add is a boolean value that makes reference to which months of the year the worker is active. For the moment, I have solved it like this:
var months_worker_1 = [{"jan":true},{"feb":true},{"mar":true},{"apr":false}] //and so on
And then, my property reads months_worker_1, but I have one array like that for each worker. I wonder if there is a way to do this that requires less lines of code, like for example, create a "master" array with all the months of the year, and in the array for each worker, specify just the months they are working. Those months become "true", and the rest of months become "false" automatically without specifying so... I have been scratching my head for some time, and for the moment only my current system is working fine, but I am guessing that there must be a simpler way...
Thanks very much!
Edit: I clarify, there is no "big picture". I am just doing some exercises trying to learn javascript and this one woke my interest, because the solution I thought seems too complicated (repeating same array many times). There is no specific goal I need to achieve, I am just learning ways to do this.

A really nice trick that I use sometimes is to use a binary number to keep track of a fixed amount of flags, and convert it to a decimal for easier storage / URL embedding / etc. Let's assume Mark, a user, is active all months of the year. Considering a binary number, in which 1 means "active" and 0 inactive, Mark's flag would be:
111111111111 (twelve months)
if Mark would only be active during january, february and december, his flag value would be:
11000000001
Checking if Mark is active during a specific months is as simple as checking if the character that corresponds to that month's index in Mark's flag is 1 or 0.
This technique has helped me in the past to send values for a large number of flags via URLs, while also keeping the URL reasonably short. Of course, you probably don't need this, but it's a nice thing to know:
Converting from binary to decimal is easy in JS:
parseInt(11000000001, 2).toString(10); // returns 1537
And the reverse:
parseInt((1537).toString(2)); // returns 11000000001
Edit
You could just as easily use an array made out of the month numbers:
var months_worker_1 = [1, 2, 3]; // this would mean that the user is active during january, february and march

Related

How to generically solve the problem of generating incremental integer IDs in JavaScript

I have been thinking about this for a few days trying to see if there is a generic way to write this function so that you don't ever need to worry about it breaking again. That is, it is as robust as it can be, and it can support using up all of the memory efficiently and effectively (in JavaScript).
So the question is about a basic thing. Often times when you create objects in JavaScript of a certain type, you might give them an ID. In the browser, for example with virtual DOM elements, you might just give them a globally unique ID (GUID) and set it to an incrementing integer.
GUID = 1
let a = createNode() // { id: 1 }
let b = createNode() // { id: 2 }
let c = createNode() // { id: 3 }
function createNode() {
return { id: GUID++ }
}
But what happens when you run out of integers? Number.MAX_SAFE_INTEGER == 2⁵³ - 1. That is obviously a very large number: 9,007,199,254,740,991 quadrillions perhaps. Many billions of billions. But if JS can reach 10 million ops per second lets say in a pick of the hat way, then that is about 900,719,925s to reach that number, or 10416 days, or about 30 years. So in this case if you left your computer running for 30 years, it would eventually run out of incrementing IDs. This would be a hard bug to find!!!
If you parallelized the generation of the IDs, then you could more realistically (more quickly) run out of the incremented integers. Assuming you don't want to use a GUID scheme.
Given the memory limits of computers, you can only create a certain number of objects. In JS you probably can't create more than a few billion.
But my question is, as a theoretical exercise, how can you solve this problem of generating the incremented integers such that if you got up to Number.MAX_SAFE_INTEGER, you would cycle back from the beginning, yet not use the potentially billions (or just millions) that you already have "live and bound". What sort of scheme would you have to use to make it so you could simply cycle through the integers and always know you have a free one available?
function getNextID() {
if (i++ > Number.MAX_SAFE_INTEGER) {
return i = 0
} else {
return i
}
}
Random notes:
The fastest overall was Chrome 11 (under 2 sec per billion iterations, or at most 4 CPU cycles per iteration); the slowest was IE8 (about 55 sec per billion iterations, or over 100 CPU cycles per iteration).
Basically, this question stems from the fact that our typical "practical" solutions will break in the super-edge case of running into Number.MAX_SAFE_INTEGER, which is very hard to test. I would like to know some ways where you could solve for that, without just erroring out in some way.
But what happens when you run out of integers?
You won't. Ever.
But if JS can reach 10 million ops per second [it'll take] about 30 years.
Not much to add. No computer will run for 30 years on the same program. Also in this very contrived example you only generate ids. In a realistic calculation you might spend 1/10000 of the time to generate ids, so the 30 years turn into 300000 years.
how can you solve this problem of generating the incremented integers such that if you got up to Number.MAX_SAFE_INTEGER, you would cycle back from the beginning,
If you "cycle back from the beginning", they won't be "incremental" anymore. One of your requirements cannot be fullfilled.
If you parallelized the generation of the IDs, then you could more realistically (more quickly) run out of the incremented integers.
No. For the ids to be strictly incremental, you have to share a counter between these parallelized agents. And access to shared memory is only possible through synchronization, so that won't be faster at all.
If you still really think that you'll run out of 52bit, use BigInts. Or Symbols, depending on your usecase.

Consider 0 number of hits for omitted dates

In this example, I draw a chart from 4 pairs of date and number of visits. I can change dataGrouping.units to day or month with sum as approximation.
For the dates that don't appear in data, I want to consider their number of visits is 0. However, the current chart looks misleading.
One way to amend that is to prepare the data manually by myself, eg, by completing data by adding all the other dates with 0 as number of visits.
Does anyone know if HighCharts provides some parameters to customize this automatically? I tried pointInterval and pointIntervalUnit, it seems they have other purposes...
It seems that you need to set xAxis.ordinal to true.
Live demo: http://jsfiddle.net/kkulig/hujdkL1L/
API reference: https://api.highcharts.com/highstock/xAxis.ordinal

Need to write an algorithm for getting sum of values from Array 1 values for each Array 2 value

I am creating a algorithm to match any combination of cells of first array to second array value with priority in second array. for example in javascript :
var arr=[10,20,30,40,50,60,70,80,90];
var arr2=[100,120,140];
what I want is to define into following logic(priority for value of second array's cell serially) automatically and please help me finding pseudo for algorithm
100 = 10+20+30+40 //arr2[0] = arr1[0] + arr1[1] + arr1[2] + arr1[3]
120 = 50+70 //arr2[1] = arr1[4] + arr1[6]
140 = 60+80 //arr2[2] = arr1[5] + arr1[7]
90 = 90 //remaining arr1[8]
values are demo and can be changed dynamically.
Solution is possible if you take both array as sorted array and then start adding elements from last ends of first array (array1) which are the greatest as array is sorted , now check if sum matches then proceed else if sum is lesser than element in array2 you were checking then you need to add third element from array1. Another case if sum is greater than element in array2 then you have to neglect one of the element from array1 you have used in addition and replace the addition with the previous element you HV used from array one. Repeat the steps. You need to think how to do this correctly or else you need to share some of your work or logic u r thinking , so that we can help
As the matter is quite complex, over and above sufficing on a pseudo code style explanation, I have also coded a practical implementation that you may find at this link.
I advise you to refrain from looking at the solution and first try to implement the algorithm yourself as there is a lot of scope for further improvement.
Here is in broad lines an explanation to the way I have decided to tackle the algorithm:
The problem presented by the OP is related to a classic example of distributing n unique elements over k unique boxes.
In this case here, arr has 9 unique elements that need to be distributed over three distinct spots, represented by the container: arr2.
So the first step in tackling this problem is to figure out how you can implement a function that given n and k, is able to calculate all the possible distributions that apply.
The closest that I could come up with was the Stirling Numbers of the Second Kind, which is defined as:
The number of ways of partitioning a set of n elements into m nonempty sets (i.e., m set blocks), also called a Stirling set number. For example, the set {1,2,3} can be partitioned into three subsets in one way: {{1},{2},{3}}; into two subsets in three ways: {{1,2},{3}}, {{1,3},{2}}, and {{1},{2,3}}; and into one subset in one way: {{1,2,3}}.
If you pay close attention to the example provided, you will realize that it pertains to the enumeration of all the distribution combinations possible over INDISTINGUISHABLE partitions as order doesn't matter.
Since in our case, each spot in the container arr2 represents a UNIQUE spot and order therefore does matter, we will thus be required to enumerate all the Stirling Combinations over every possible combination of arr2.
Practically speaking, this means that for our example where arr2.length === 3, we will be required to apply all of the Stirling Combinations obtained to [100,120,140], [120,140,100], [140,100,120] etc.(in total 6 permutations)
The main challenging part here is to implement the Stirling Function, but luckily somebody has already done so:
http://blogs.msdn.com/b/oldnewthing/archive/2014/03/24/10510315.aspx
After copy and pasting the Stirling Function and using it to distribute arr over 3 unique spots, you now need to filter out the distributions that don't sum up to the designated spots encompassed by arr2.
This will then leave you with all the possible solutions that apply. In your case, for
var arr=[10,20,30,40,50,60,70,80,90];
var arr2=[100,120,140];
no solutions apply at all.
A quick workaround to that is by expanding the distribution target arr2 from [100,120,140] to [100,120,140,90]. A better workaround is that in the case zero solutions are found, then take away one element from list arr until you obtain a solution. Then you can later on expand your solution sets by including this element where it represents a mapping of it unto itself.

How to determine a value based on dynamic ranges in Javascript

Is there a clever way to determine, say an array index, that falls within a given range? The application is similar to a playlist for a single video file with a set of from/to times that denote a "chapter".
i.e. Chapters:
00:01 - 00:30 : Call To Order
00:31 - 00:45 : Pledge of Allegence
00:46 - 02:25 : Opening Remarks
02:26 - 32:07 : Old Business
etc., etc., etc.
I have a list of these items on the page, and as the player reports where in the video it is currently playing by returning the current timestamp, I need to use jQuery to highlight the LI of the "chapter" in which the currently video timestamp falls. So if the video is currently at 1:15, that's "Opening Remarks", and the 3rd list item would be highlighted.
I've tried a number of approaches, but ultimately use PHP to write a huge series of IF/ELSEs because a playlist could have anywhere from 5 to 100 different Chapters in it and can be modified by the user at any time.
Ideally, I'd like an array using the Start time as the Key and chapter as the value, and a function that returns the first index that is >= the current timestamp. Is there any clever approach to accomplishing this? My way "works", but good God, its inefficient, running through 100 if/elses 10 times per second.
P.S. I should mention that all values are actually in seconds, with the question using H:M:S for clarity. Ultimately, I'm trying to understand how to select an array index if it falls within a given range.
Something like this:
var chapters = {
1: "callToOrder",
31: "pledgeOfAllegiance",
46: "openingRemarks",
146: "oldBusiness",
}
function currentChapter(seconds) {
var start, found = Infinity;
for (start in chapters) {
if (start <= seconds && start < found) {
found = start;
}
}
return (found === Infinity) ? null : chapters[found];
}
It will run in linear time in the number of chapters. In practice, this should be acceptable. If it isn't, then you could replace chapters with an array of objects and perform a binary search.

How do I set up an automated "Quote of the day"?

I am in charge of a website, and I have set up a "Quote of the Day" which currently is quite simplistic. See Here (on the right of the page)
What it currently does is it gets the Day of the month and the month, and normalises to one, then multiplies by the number of quotes (stored in an xml file) and rounds down. While this method will give me the same quote whichever machine I am on (something a random number generator could never do) it has been pointed out to me that this method is flawed. If you consider January the first couple quotes are going to be the same, 1*1/360, 2*1/360, 3*1/360, thus the quote isn't unique.
Can anyone think of a better way to select a quote of the day?
Fun question. Instead of relying on days of the month, why not count days since a given date? JS provides a pretty good property for that: getTime(), which gives you the number of milliseconds since 12am UTC on Jan. 1 1970, which you can convert to days with some simple division.
The only thing that complicates it is that if you expect your quotes to shift at midnight (and who doesn't?), you have to take into account the timezone. Again, JS provides that with getTimezoneOffset(), which gives the number of minutes ahead or behind the user's locale is compared to UTC. If you want ALL users to flip at the same time, regardless of where they live, just set this to a static value.
Your code could look something like this:
var intQuoteCount = 51; // The number of quotes in your library
var dtNow = new Date();
var intTZOffset = dtNow.getTimezoneOffset() * 60000; // automatically adjust for user timezone
var intNow = dtNow.getTime() - intTZOffset;
var intDay = Math.floor(intNow / 86400000); // The number of 'local' days since Jan 1, 1970
var intQuoteToDisplay = intDay % intQuoteCount;
True, determinism is something "a random number generator could never do". Fortunately (for this case, at least), programming languages provide pseudo-random number generators, not the real thing. The pseudo-random numbers are generated by doing a bunch of calculations on a "seed" value.
To get a repeatable "random" selection, then, all you need to do is set the seed in a way which is consistent for each day - I would suggest using the date, in "yyyymmdd" format, as the seed, but any other number which will be unchanged over the course of a day will work just as well.
Once you have your seed, tell the PRNG to use it with the command srand(mySeed); and you'll get the same sequence of "random" numbers from rand() every time (until mySeed changes).
If you want to show the quotes in order, you could get the current Julian Day number, which will increase by one each day, and take the reminder after dividing it by the number of quotes as the number of today's quote. If you want to show all quotes but the order of them to change each cycle, you can xor the quote number and rearrange the bits using some logic that you get from the quotient of the division.
You could try rounding up on an even day and rounding down on an odd day. But I'm am sure there is better ways, this is just quick suggestion.
Also you could try using the current day of the year in the calculation as this is unique for each new day in the year as opposed to repeating each month.
Do you have to limit yourself to having a cycle of 360 days? If you have for example 500 quotes. some might never be used.
How about- Every day pick a random number between 1 and #OfQoutes, use it as the quote of day index, and mark it as "used in current cycle".
Next time when you pick a number, if you pick a quote that is marked as "used in current cycle" re-pick until you get a number of quote which isn't marked so. When all quotes are marked, un-mark all of them.
This will ensure you're going through all quotes in each cycle, together with randomness, and it will obviously work for any number of quotes.
<body onLoad="thoughts_authors()">
<script>
function thoughts_authors()
{
var authors=new Array()
authors[0] = "Charles Schulz";
authors[1] = "Jack Wagner";
authors[2] = "Mark Twain";
authors[3] = "Oscar Wilde";
authors[4] = "David Letterman";
authors[5] = "Lily Tomlin";
var thoughts=new Array()
thoughts[0] = "Good Day Is Today";
thoughts[1] = "Style Is What You Choose";
thoughts[2] = "Be The Best Version Of You.";
thoughts[3] = "Truth Along Triumphs.";
thoughts[4] = "How can Life Be Devastating When YOU Are Present in It.";
thoughts[5] = "Believe In What You Say";
index = Math.floor(Math.random() * thoughts.length);
alert(thoughts[index]+ "-" + authors[index]);
}
</script>
THIS WILL GENERATE RANDOM QUOTES ALONG WITH RANDOM AUTHORS

Categories