Brief introduction
Stream.js is a small JS library that handles stream-related operations. The stream here refers to a data structure that, like an array, can place multiple types of data, but does not limit the length or even infinity. The data structure can be retrieved, modified, appended and other operations. Since its length is not limited to this feature, it is significantly different from the data structure in the usual sense.
Api
Stream provides an API that contains three types.
The first is the creation of classes. Including:
- The second parameter of the new stream (head, Functionreturingtail) is a method that puts back the remaining elements in addition to the first element, so it may also return a stream, which is a new stream constructed from one or more existing streams. Of course, these two parameters are not necessary, if not filled, it is an empty stresam.
- Stream.make () is equivalent to a static method, it is relatively simple, directly fill in the data inside the line.
- Stream.range (from, to) returns a stream of all the numbers from the to center, and if not, the default is the natural number.
The second type is the query class, which includes:
- Head () returns the first item in a stream
- Item (index) returns the item at the index position
- Tail () returns the remaining elements in the first position
- Empty () is null
The third type of traversal operation includes:
- Map () is analogous to a map in an array, which is actually a mapping process
- Walk () is also traversed, but does not have a direct effect on the element
- Filter () filters out certain elements, which accept the case that the parameter is a function
- Take (n) takes the first n elements
- Scale (n) multiplies each element by n
Chestnut recursive call construct stream
As mentioned earlier, the second argument of a constructor can be a method that returns a stream, if it calls itself? It also constitutes an infinitely long stream with the same number.
function ones () { returnnew Stream ( // The first element of the stream of ones is 1 ... 1, // and the rest of the elements of this stream is given by calling the function ones () (This same function!) ones );
Add the Stream
What happens if an infinitely long stream is added to another infinitely long stream? As follows:
functionones () {return NewStream (1, ones); } functionnaturalnumbers () {return NewStream (//The natural numbers is the stream whose first element is 1 ... 1, function () { //And the rest is the natural numbers all incremented by one //which is obtained by adding the stream of natural numbers ... //1, 2, 3, 4, 5, ... //To the infinite stream of ones ... //1, 1, 1, 1, 1, ... //Yielding ... //2, 3, 4, 5, 6, ... //which indeed is the REST of the natural numbers after one returnones (). Add (Naturalnumbers ()); } ); }
Although it can be seen from the name, it is a natural number, but for the first time it does seem confusing. You might want to make a list:
Set result = (1, N1, N2, N3, ....) )
Also (N1, N2, N3, ...) = (1, 1, 1, ...) + (1, N1, N2, N3, ...)
So n1 = 2, N2 = 1 + n1 = 3, N3 = 1 + n2 = 4, ... So the next number is always 1 more than the previous number, then the natural number!
Code parsing
When I first looked at the code, I was surprised, although the API has so many, but the entire code only has Paraya line, is really very small.
First, you define a class stream, set its head and get the function that is used for the remainder.
function Stream (head, tailpromise) { if (typeof head! = ' undefined ' Span style= "color: #000000;" ) { this . Headvalue = head; if (typeof tailpromise = = " Undefined ' ) {Tailpromise = function
() {
return
new
Stream (); };
this . Tailpromise =
tailpromise;}
The next step is to open the API directly on the prototype, noting that because of its infinitely long nature, it cannot go through an index as if it were traversing an array, but rather like a linked list, which is obtained through the next pointer, which is acquired through the tail () method.
var This ; while (n! = 0 ) {--n ; Try { = s.tail (); } Catch (e) { thrownew Error (' Item index does not exist in stream. ') ); } }
Of course, if you make a map of an infinitely long stream, it's certainly not going to be a truly one-off map, but it's re-constructing a stream that defines the new rule, head = f (head), tail = tail (). Map (f), So the function is only executed when the data is taken.
map: function (f) { if (this .empty ()) { return this ; var self = this ; return new Stream (f (this . Head ()), function () { return Self.tail (). map (f); } ); }
The other API methods are the same, I think the most important feature of the implementation is: recursive call! A stream no matter how long, I divide it into two parts: one element is the head, the remainder is the tail. Then to do is to operate on the head, the tail to operate a bit. For example, when constructing a stream of Rarnge to Low-high, just set the head to low, and the tail is low+1 to high.
return New function () { return stream.range (low + 1, high); });
Stream is a kind of headelement + tailstream structure, because Tailstream can be further divided, so it is inevitable to implement various operations by recursion. It is an effective way to deal with an infinitely long sequence, and it is much clearer if we associate it with the linked list in the data structure.
Every day to see a piece of Code series (a): Stream.js