Stream. js is a small, completely independent Javascript class library.

Source: Internet
Author: User

<Script src = 'stream-min. js'> </script>
Download stream. js
2 kb minified

What is streams?
Streams is a simple and easy-to-use data structure, like arrays or chain tables, but with some extraordinary capabilities.

What are their special characteristics?
Unlike arrays, streams is a magic data structure. It can load infinite elements. Yes, you have not heard the error. This magic comes from the ability to perform lazily. This simple term indicates that they can load an infinite number of elements.

Getting started
If you are willing to spend 10 minutes reading this article, your understanding of programming may be completely changed (unless you have experience in functional programming !). Please be patient. Let me introduce the basic functions supported by streams that are similar to those supported by arrays or chain tables. Then I will introduce some very interesting features like you.

Stream is a container. It can accommodate elements. You can use Stream. make to load some elements of a stream. You only need to pass the desired element as a parameter:

Var s = Stream. make (10, 20, 30); // s is now a stream containing 10, 20, and 30
It's easy enough. Now s is a stream with three elements: 10, 20, and 30; in order. We can use s. length () to view the stream length, and use s. item (I) to retrieve an element from the index. You can also call s. head () to obtain the first element of the stream. Let's perform the following operations:
Copy codeThe Code is as follows:
Var s = Stream. make (10, 20, 30 );
Console. log (s. length (); // outputs 3
Console. log (s. head (); // outputs 10
Console. log (s. item (0); // exactly equivalent to the line above
Console. log (s. item (1); // outputs 20
Console. log (s. item (2); // outputs 30

This page has loaded the stream. js class library. If you want to run these examples or write a few words on your own, simply open the Javascript console of your browser and run it directly.

We can also use new Stream () or directly use Stream. make () to construct an empty stream. You can use the s. tail () method to obtain all the elements except the first element in the stream. If you call the s. head () or s. tail () method on an empty stream, an exception is thrown. You can use s. empty () to check whether a stream is null. It returns true or false.
Copy codeThe Code is as follows:
Var s = Stream. make (10, 20, 30 );
Var t = s. tail (); // returns the stream that contains two items: 20 and 30
Console. log (t. head (); // outputs 20
Var u = t. tail (); // returns the stream that contains one item: 30
Console. log (u. head (); // outputs 30
Var v = u. tail (); // returns the empty stream
Console. log (v. empty (); // prints true

In this way, all elements in a stream can be printed:
Copy codeThe Code is as follows:
Var s = Stream. make (10, 20, 30 );
While (! S. empty ()){
Console. log (s. head ());
S = s. tail ();
}

We have a simple method to implement this: s. print () will print all the elements in the stream.

What else can we do with them?
Another simple function is the Stream. range (min, max) function. It returns a stream containing a natural number from min to max.
Copy codeThe Code is as follows:
Var s = Stream. range (10, 20 );
S. print (); // prints the numbers from 10 to 20
On this stream, you can use functions such as map, filter, and walk. S. map (f) accepts a parameter f, which is a function. All elements in stream are processed by f. Its return value is the stream processed by this function. So, for example, you can use it to double the number in your stream:

Function doubleNumber (x ){
Return 2 * x;
}

Var numbers = Stream. range (10, 15 );
Numbers. print (); // prints 10, 11, 12, 13, 14, 15
Var doubles = numbers. map (doubleNumber );
Doubles. print (); // prints 20, 22, 24, 26, 28, 30

It's cool, isn't it? Similar, s. filter (f) also accepts a parameter f, which is a function. All elements in stream are processed by this function. Its return value is also a stream, but only contains elements that allow the f function to return true. Therefore, you can use it to filter certain elements in your stream. Let's use this method to construct a new stream containing only an odd number based on the previous stream:
Copy codeThe Code is as follows:
Function checkIfOdd (x ){
If (x % 2 = 0 ){
// Even number
Return false;
}
Else {
// Odd number
Return true;
}
}
Var numbers = Stream. range (10, 15 );
Numbers. print (); // prints 10, 11, 12, 13, 14, 15
Var onlyOdds = numbers. filter (checkIfOdd );
OnlyOdds. print (); // prints 11, 13, 15

Very effective, isn't it? The last s. the walk (f) method also accepts a parameter f, which is a function. All elements in stream must be processed by this function, but it does not affect the stream. The idea of printing all elements in stream comes with a new implementation method:
Copy codeThe Code is as follows:
Function printItem (x ){
Console. log ('the element is: '+ x );
}
Var numbers = Stream. range (10, 12 );
// Prints:
// The element is: 10
// The element is: 11
// The element is: 12
Numbers. walk (printItem );

Another useful function is s. take (n). The stream returned by this function only contains the first n elements of the original stream. This is useful when it is used to intercept a stream:
Copy codeThe Code is as follows:
Var numbers = Stream. range (10,100); // numbers 10... 100
Var fewerNumbers = numbers. take (10); // numbers 10... 19
FewerNumbers. print ();

Other useful things: s. scale (factor) is multiplied by all elements in stream by factor. s. add (t) adds each element of stream s to the corresponding element of stream t, and returns the result after addition. Let's look at several examples:
Copy codeThe Code is as follows:
Var numbers = Stream. range (1, 3 );
Var multiplesOfTen = numbers. scale (10 );
MultiplesOfTen. print (); // prints 10, 20, 30
Numbers. add (multiplesOfTen). print (); // prints 11, 22, 33

Although we currently see operations on numbers, stream can load anything: strings, Boolean values, functions, objects, and even other arrays or streams. However, please note that some special values: null and undefined cannot be loaded in stream.

I want to show you the magic!
Now, let's deal with an infinite number. You do not need to add infinite elements to stream. For example, in Stream. in the range (low, high) method, you can ignore its second parameter and write it as Stream. range (low). In this case, the data has no upper limit, so this stream loads all the natural numbers from low to infinity. You can also ignore the low parameter. The default value of this parameter is 1. In this case, Stream. range () returns all natural numbers.

Does this require your infinite amount of memory/time/processing capabilities?
No, no. This is the most exciting part. You can run these codes. They run very fast, just like a normal array. The following is an example of printing from 1 to 10:
Copy codeThe Code is as follows:
Var naturalNumbers = Stream. range (); // returns the stream containing all natural numbers from 1 and up
Var oneToTen = naturalNumbers. take (10); // returns the stream containing the numbers 1... 10
OneToTen. print ();

You are deceiving
Yes, I am lying. The key is that you can think of these structures as Infinity, which introduces a new programming paradigm, a code dedicated to simplicity, it makes your code easier to understand than conventional imperative programming, and closer to the programming paradigm of natural mathematics. This Javascript class library is very short and small; it is designed according to this programming paradigm. Let's use it more than one. We construct two streams and load all odd numbers and even numbers respectively.
Copy codeThe Code is as follows:
Var naturalNumbers = Stream. range (); // naturalNumbers is now 1, 2, 3 ,...
Var evenNumbers = naturalNumbers. map (function (x ){
Return 2 * x;
}); // EvenNumbers is now 2, 4, 6 ,...
Var oddNumbers = naturalNumbers. filter (function (x ){
Return x % 2! = 0;
}); // OddNumbers is now 1, 3, 5 ,...
EvenNumbers. take (3). print (); // prints 2, 4, 6
OddNumbers. take (3). print (); // prints 1, 3, 5

It's cool, isn't it? Stream is more powerful than array. Now, let me talk about stream in a few minutes. You can use new Stream () to create an empty stream, and use new Stream (head, functionReturningTail) to create a non-empty stream. For this non-empty stream, the first parameter you pass in becomes the Header element of the stream, and the second parameter is a function, it returns the end of the stream (a stream with more than all elements), which is probably an empty stream. Confused? Let's take an example:
Copy codeThe Code is as follows:
Var s = new Stream (10, function (){
Return new Stream ();
});
// The head of the s stream is 10; the tail of the s stream is the empty stream
S. print (); // prints 10
Var t = new Stream (10, function (){
Return new Stream (20, function (){
Return new Stream (30, function (){
Return new Stream ();
});
});
});
// The head of the t stream is 10; its tail has a head which is 20 and a tail which
// Has a head which is 30 and a tail which is the empty stream.
T. print (); // prints 10, 20, 30

Is it okay? You can directly use Stream. make (10, 20, 30) to do this. However, please note that we can easily build our infinite stream in this way. Let's make an endless stream:
Copy codeThe Code is as follows:
Function ones (){
Return new Stream (
// The first element of the stream of ones is 1...
1,
// And the rest of the elements of this stream are given by calling the function ones () (this same function !)
Ones
);
}

Var s = ones (); // now s contains 1, 1, 1, 1 ,...
S. take (3). print (); // prints 1, 1, 1

Please note that if you use s. print () on an infinitely large stream, it will print it all at once and eventually consume your memory. Therefore, you 'd better use s. take (n) before s. print ). Use s. length () is also meaningless, all, do not do these operations; it will lead to an endless loop (trying to reach the end of an endless stream ). However, for an infinite stream, you can use s. map (f) and s. filter (f ). However, s. walk (f) is not good for infinite stream. All, there are some things you should remember; for an infinitely infinite stream, we must use s. take (n) to retrieve the finite part.

Let's see if we can do something more interesting. There is also an interesting way to create a stream containing natural numbers:

Copy codeThe Code is as follows:
Function ones (){
Return new Stream (1, ones );
}
Function naturalNumbers (){
Return new Stream (
// The natural numbers are the stream whose first element is 1...
1,
Function (){
// And the rest are 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 are the REST of the natural numbers after one
Return ones (). add (naturalNumbers ());
}
);
}
NaturalNumbers (). take (5). print (); // prints 1, 2, 3, 4, 5

Careful readers will find out why the second parameter of the newly constructed stream is a function that returns the end, not the end. In this way, the tail truncation operation can be delayed to prevent endless execution periods.

Let's look at a more complex example. The following is an exercise left for readers. What is the code below?
Copy codeThe Code is as follows:
Function sieve (s ){
Var h = s. head ();
Return new Stream (h, function (){
Return sieve (s. tail (). filter (function (x ){
Return x % h! = 0;
}));
});
}
Sieve (Stream. range (2). take (10). print ();

It takes some time to understand the purpose of this Code. Unless you have functional programming experience, most programmers will find this piece of code hard to understand, so if you cannot immediately see it, don't feel frustrated. Let's give you a tip: find out what is the Header element of the printed stream. Then find out what the second element is (the Header element of the remaining element); then the third element and the fourth element. The function name also gives you some tips.

If you are interested in this kind of problem, here are some more.

If you really don't know what this code is, run it and take a look! In this way, you can easily understand how it works.

Salute
Streams is not actually a new idea. Many functional programming languages support this feature. The so-called 'stream' is the name in Scheme, and Scheme is a dialect of LISP. The Haskell language also supports an infinite list ). The 'Ta', 'tail', 'head', 'map', and 'filter' names are all from the Haskell language. Python is similar to many other languages, but it is called generators )".

These ideas have been circulating in the functional programming community for a long time. However, it is a new concept for most Javascript programmers, especially those who do not have functional programming experience.

Many examples and ideas here are from the book Structure and Interpretation of Computer Programs. If you like these ideas, I highly recommend you read them. This book is available for free online. It is also the creative source for developing this Javascript class library.

If you like stream in other syntaxes, you can try linq. js or, if you use node. js, node-lazy may be more suitable for you.

If you like CoffeeScript, Michael Blume is porting stream. js to CoffeeScript to create coffeestream.

Thank you for reading this article!
I hope you will enjoy stream. js. This class library is free of charge, so if you like it or it can help you in some way, you can consider buying me a cup of hot chocolate drink (I don't drink coffee) or write to me. If you want to do this, please write down where you are and what you do. I like to collect pictures from all over the world. Therefore, please attach a picture you have taken in your city!

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.