The use of Ruby enumerations is detailed

Source: Internet
Author: User
Tags comparable comparison hash instance method join mixed

Get enumeration capabilities from each

The Class you want to enumerate has to have a each method, and its job is to yield the project to a code block, one at a time.

Each does things differently on different classes, such as on an array, each yield the first item, then the second, and the third ... In the hash, the yield is key/value as an array of two elements. On file processing, one line of content is yield at a time. The range iteration first looks at the possibility of iterating and then pretends it is an array. Define each method in your own class, it means you define it, as long as it yield something.

First write a class, understand how enumerable is going on. Rainbow Rainbow, yield one color at a time:

Class Rainbow
Include Enumerable

def each
Yield ' red '
Yield ' orange '
Yield ' yellow '
Yield ' green '
Yield ' Blue '
Yield ' indigo '
Yield ' violet '
End
End
Use each method:

r = Rainbow.new
R.each do |color|
Puts "Next color: #{color}"
End
Results of execution:

Next color: Red
Next color: orange
Next color: Yellow
Next color: Green
Next color: Blue
Next color: Indigo
Next color: Violet
The Rainbow is mixed with enumerable modules so that Rainbow instances automatically have a whole bunch of methods based on each creation.

Find, returning true in the code block returns the first element. For example, to find the first Y-start color:

Y_color = r.find {|color| color.start_with? (' Y ')}
Puts "The first color to start with Y is: #{y_color}"
The result:

The first color to start with Y is: yellow
Find calls the Each,each yield project, where you can test one project at a time in a code block. When each yield yellow, the Find code block passes the test, and the Y_color value is yellow.

Let's see what's in enumerable:

>> Enumerable.instance_methods (false). Sort
=> [: All],: Any?,: Chunk,: Chunk_while,: Collect,: Collect_concat,: Count,: Cycle,:d etect,:d ROP,:d rop_while,: Each_c ONS,: each_entry,: Each_slice,: Each_with_index,: Each_with_object,: Entries,: Find,: Find_all,: Find_index: Flat_map,: grep,: Grep_v,: group_by,: Include?,: Inject,: lazy,: Map,: Max,: max_by,: Member?: Min,: min_by, Minmax,: mi Nmax_by,: None?,: One?,:p artition,: Reduce,: Reject,: Reverse_each,: Select,: Slice_after,: Slice_before,: Slice_when,: Sort,: sort_by,: Take,: Take_while,: to_a,: To_h,: To_set,: Zip]
Enumerating Boolean queries

Some enumeration methods return True or false based on a specific criterion that matches one or more elements.

Try these:

>> provinces = ["Shandong", "Shanxi", "Heilongjiang"]
=> ["Shandong", "Shanxi", "Heilongjiang"]
>> provinces.include? ("Shandong")
=> true
>> Provinces.all? {|province| Province =~/Mountain/}
=> false
>> Provinces.any? {|province| Province =~/Mountain/}
=> true
>> Provinces.one? {|province| province =~/Black/}
=> true
>> Provinces.none? {|province| province =~/River/}
=> true
Continue the experiment:

>> provinces = {' Shandong ' => ' Lu ', ' Shanxi ' => ' Jin ', ' Heilongjiang ' => ' black '}
=> {"Shandong" => "Lu", "Shanxi" => "Jin", "Heilongjiang" => "BLACK"}
>> provinces.include? ("Shandong")
=> true
>> Provinces.all? {|province, abbr| province =~/Mountain/}
=> false
>> Provinces.one? {|province, addr| province =~/Black/}
=> true
You can also change a method:

>> Provinces.keys.all? {|province, abbr| province =~/Mountain/}
=> false
Hash

Each iteration of a hash, the hash will be yield into your code block, each time a key/value pair. Each pair is an array of two elements.

Range

>> r = range.new (1, 10)
=> 1..10
>> R.one? {|n| n = = 5}
=> true
>> R.none? {|n| n% 2 = 0}
=> false
>> r = Range.new (1.0, 10.0)
=> 1.0..10.0
>> R.one {|n| n = 5}
Nomethoderror:undefined method ' One ' for 1.0..10.0:range
Did you mean? One?
From (IRB): 402
From/usr/local/bin/irb:11:in ' <main> '
>> r = range.new (1, 10.3)
=> 1..10.3
>> R.any? {|n| n > 5}
=> true
Enumeration Search and Selection

Filters the objects of a collection based on one or more criteria. Select an item in the object of a collection based on one or more criteria. Let's look at the filtering and search methods, which are iterators, and they all expect you to provide a block of code. Define the selection criteria in the code block.

Find first match

Find or Detect. Example: An array of integers finds the first number greater than 5:

>> [1,2,3,4,5,6,7,8,9,10].find {|n| n > 5} => 6
Find iterates through the entire array, each time yield an element to the code block. method returns True, the element that is yield wins, and then stops the iteration.

The element cannot be tested by a block of code, and the method returns nil.

Find_all and Reject

Find_all is also named SELECT. The new collection returned contains all the items that match. Nothing is found. Returns a blank collection object.

>> a = [1,2,3,4,5,6,7,8,9,10]
=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
>> A.find_all {|item| Item >5}
=> [6, 7, 8, 9, 10]
>> a.select {|item| item > 100}
=> []
Reject

>> a.reject {|item| item > 5}
=> [1, 2, 3, 4, 5]
Grep

Enumerable#grep method, based on = = operator selection.

>> colors =%w{red orange yellow green Blue Indigo Violet}
=> ["Red", "orange", "Yellow", "green", "Blue", "Indigo", "Violet"]
>> Colors.grep (/o/)
=> ["Orange", "Yellow", "Indigo", "Violet"]
Try again:

>> Miscellany = [A, ' Hello ', 10..20, ' goodbye ']
=> [, "Hello", 10..20, "Goodbye"]
>> Miscellany.grep (String)
=> ["Hello", "Goodbye"]
>> Miscellany.grep (50..100)
=> [75]
The function of enumerable.grep (expression) is equivalent to:

Enumerable.select {|element| expression = = element}
Provides a code block for grep:

>> colors =%w{red orange yellow green Blue Indigo Violet}
=> ["Red", "orange", "Yellow", "green", "Blue", "Indigo", "Violet"]
>> Colors.grep (/o/) {|color| color.capitalize}
=> ["Orange", "Yellow", "Indigo", "Violet"]
Grammar:

Enumerable.grep (expression) {|item| ...}
Equivalent:

Enumerable.select {|item| expression = = Item}.map {|item| ...}
Group_by

Group, try:

>> colors =%w{red orange yellow green Blue Indigo Violet}
=> ["Red", "orange", "Yellow", "green", "Blue", "Indigo", "Violet"]
>> colors.group_by {|color| color.size}
=> {3=>["red"], 6=>["orange", "Yellow", "Indigo", "Violet"], 5=>["green"], 4=>["Blue"}
Partition

>> colors.partition {|color| color.size > 5}
=> [["Orange", "Yellow", "Indigo", "Violet"], ["Red", "green", "blue"]]
A person class, each has an age, there is a teenager? instance method, which returns true if the person's age is between 13-19.

Class Person
Attr_accessor:age
def initialize (options)
Self.age = Options[:age]
End
DEF teenager?
(13..19) = = Age
End
End
To generate a group of people:

>> people = 10.step (25,3). Map {|i| Person.new (: Age => i)}
=> [#<person:0x007fa7e39b2110 @age =10>, #<person:0x007fa7e39b20c0 @age =13>, #<person:0 X007fa7e39b1ff8 @age =16>, #<person:0x007fa7e39b1fa8 @age =19>, #<person:0x007fa7e39b1f58 @age =22> <person:0x007fa7e39b1ee0 @age =25>]
Teens:

>> teens = people.partition {|person| Person.teenager?}
=> [[#<person:0x007fa7e39b20c0 @age =13>, #<person:0x007fa7e39b1ff8 @age =16> #<person:0 X007fa7e39b1fa8 @age =19>], [#<person:0x007fa7e39b2110 @age =10>, #<person:0x007fa7e39b1f58 @age =22>, # <person:0x007fa7e39b1ee0 @age =25>]]
How many young people? How much is not

>> puts "#{teens[0].size} teens; #{teens[1].size} non-teens "
3 teens; 3 Non-teens
=> Nil
Iterative operations

The

>> [1,2,3,4].first
=> 1
>> (1..10).
=> 1
>> {1 => "one", 2 => "two"}.first
=> [1, "one"]
The first method returns an object that is the same as the one you used each time to yield.

>> hash = {3 => "three", 1 => "one", 2 => "two"}
=> {3=> "Three", 1=> "one", 2=> "two"}
>> Hash.first
=> [3, "three"]
>> hash[3] = "Trois"
=> "Trois"
>> Hash.first
=> [3, "Trois"]
Take and Drop method

2016-09-13 07:33 * *

Take take, drop throw.

>> provinces =%w{Hegi Liao Jing Jin hu}
=> ["Black", "Ji", "Liao", "Jing", "Jin", "Shanghai"]
>> Provinces.take (2)
=> ["Black", "Ji"]
>> Provinces.drop (2)
=> ["Liao", "Jing", "Jin", "Hu"]
Take_while and Drop_while, you can provide a block of code.

>> provinces =%w{Shandong Shanxi Henan Hebei}
=> ["Shandong", "Shanxi", "Henan", "Hebei"]
>> provinces.take_while {|p|/Mt/.match (P)}
=> ["Shandong", "Shanxi"]
>> provinces.drop_while {|p|/river/.match (P)}
=> ["Shandong", "Shanxi", "Henan", "Hebei"]
Min and Max methods

>> [1,2,3].max
=> 3
>> [1,2,3].min
=> 1
The minimum and maximum is determined by <=>.

Min_by and max_by to provide them with a block of code.

>> ["Hi", "Hello"].min_by {|w| w.size}
=> "HI"
>> ["Hi", "Hello"].max_by {|w| w.size}
=> "Hello"
Minmax and Minmax_by, the smallest of the largest.

>> [1,2,3].minmax
=> [1, 3]
Hash, with key to determine, want to use value to determine, you can use the *_by method to provide a block of code.

>> n = {1 => "one", 2 => "Two", 3 => "three"}
=> {1=> "One", 2=> "two", 3=> "three"}
>> N.min
=> [1, "one"]
>> N.max
=> [3, "three"]
>> n.max_by {|k, v| v}
=> [2, "two"]
>> n.min_by {|k, v| v}
=> [1, "one"]
Each of the relatives

Reverse_each

>> [1,2,3].reverse_each {|e| puts E * 10}
30
20
10
=> [1, 2, 3]
Each_with_index

>> provinces = ["Black", "Ji", "Liao"]
=> ["Black", "Ji", "Liao"]
>> Provinces.each_with_index do |p, i|
?> puts "#{i+1}. #{p} "
>> End
1. Black
2. Ji
3. Liao
=> ["Black", "Ji", "Liao"]
Each_index

>>%w{a b c}.each_index {|i| puts i}
0
1
2
=> ["A", "B", "C"]
Hash

>> letters = {"A" => "Ay", "B" => "Bee", "C" => "" "
=> {"A" => "Ay", "B" => "Bee", "C" => "You"}
>> Letters.each_with_index {| ( K,V), i| Puts i}
0
1
2
=> {"A" => "Ay", "B" => "Bee", "C" => "You"}
>> Letters.each_index {| ( K,V), i| Puts i}
nomethoderror:undefined method ' Each_index ' for {"A" => "Ay", "B" => "Bee", "C" => "You"}:hash
Did you mean? Each_with_index
From (IRB): 31
From/usr/local/bin/irb:11:in ' <main> '
Each_slice and Each_cons

>> array = [1,2,3,4,5,6,7,8,9,10]
=> [1, 2, 3, 4, 5, 6, 7, 8, 9, ten]
>> Array.each_slice (3) {|SL ice| P Slice}
[1, 2, 3]
[4, 5, 6]
[7, 8, 9]
[ten]
=> nil
>> array.each_cons (3) {|cons| P cons}< br> [1, 2, 3]
[2, 3, 4]
[3, 4, 5]
[4, 5, 6]
[5, 6, 7]
[6, 7, 8]
[7, 8, 9]
[8, 9,]
=> Nil
Cycle

Class Playingcard
Suits =%w{clubs Diamonds Hearts Spades}
Ranks =%w{2 3 4 5 6 7 8 9 J Q K A}
Class Deck
Attr_reader:cards
def initialize (n=1)
@cards = []
Suits.cycle (n) do |s|
Ranks.cycle (n) do |s|
@cards << "#{r} of #{s}"
End
End
End
End
End
Cases:

Deck = Playingcard::D eck.new (2)
The state is not good, look back again this method.
Inject

Inject,reduce.

An array summation, ACC represents accumulator:

>> [1,2,3].inject (0) {|acc,n| ACC + n}
=> 6
Let's see what happens:

>> [1,2,3].inject do |acc,n|
?> puts "adding #{acc} and #{n}...#{acc+n}"
>> ACC + N
>> End
Adding 1 and 2...3
Adding 3 and 3...6
=> 6
Map

Map (collect). Always returns an array of the same size as the original array.

>> names =%w{David Yukihiro Chad Amy}
=> ["David", "Yukihiro", "Chad", "Amy"]
>> names.map {|name| Name.upcase}
=> ["DAVID", "Yukihiro", "CHAD", "AMY"]
Value returned by map

The map returns the new object:

result = array.map {|x| # code here ...}
Do an experiment:

>> array = [1,2,3]
=> [1, 2, 3]
>> result = Array.map {|n| puts n * 100}
100
200
300
=> [Nil, nil, nil]
result is [nil, nil, nil] because the puts return value is nil.

In-place Mapping

map! is defined in the Array, it is not in the enumerable.

Experiment:

>> names =%w{David Yukihiro Chad Amy}
=> ["David", "Yukihiro", "Chad", "Amy"]
>> names.map! (&:upcase)
=> ["DAVID", "Yukihiro", "CHAD", "AMY"]
Enumeration string

Iteration bytes with Each_bype:

>> str = "ABCDE"
=> "ABCDE"
>> str.each_byte {|b| P B}
97
98
99
100
101
=> "ABCDE"
What you want is not the byte code, but the character, which you can use Each_char:

>> str = "ABCDE"
=> "ABCDE"
>> Str.each_char {|b| P B}
A
"B"
C
"D"
E
=> "ABCDE"
Code point:

>> str = "100\U20AC"
=> "100€"
>> str.each_codepoint {|cp| p CP}
49
48
48
8364
=> "100€"
BYTE by byte:

>> str.each_byte {|b| P B}
49
48
48
226
130
172
=> "100€"
Line by line, with Each_line:

>> str = "This string\nhas three\nlines"
=> "This String\nhas three\nlines"
>> str.each_line {|l| puts "next line: #{l}"}
Next Line:this string
Next Line:has Three
Next Line:lines
=> "This String\nhas three\nlines"
Depending on the value of the global variable $/, you can change the value of this variable:

>> str = "I!love!you"
=> "I!love!you"
>> $/= "!"
=> "!"
>> str.each_line {|l| puts "next line: #{l}"}
Next line:i!
Next line:love!
Next line:you
=> "I!love!you"
Bytes,chars,codepoints,lines of the array:

>> str = "Hello"
=> "Hello"
>> P Str.bytes
[104, 101, 108, 108, 111]
=> [104, 101, 108, 108, 111]
>> P Str.chars
["H", "E", "L", "L", "O"]
=> ["H", "E", "L", "L", "O"]
>> P str.codepoints
[104, 101, 108, 108, 111]
=> [104, 101, 108, 108, 111]
>> P Str.lines
["Hello"]
=> ["Hello"]
Storing enumerations

You have a class, you want to arrange multiple instances in order, you need to:

Create a comparison method (<=>) in the class.
Put multiple instances into a container, such as an array.
Sort the container.
The ability to sort is enumerable, you don't need to mix the modules in your class, you can put your objects in a enumerable container. This container object can be enumerated, and you can sort the collection using sort and sort_by.

To sort a numeric array:

>> [3,2,5,1,4].sort
=> [1, 2, 3, 4, 5]
Sorting numbers is easy, if you want to sort a set of paintings?

>> [PA1, PA2, Pa3, PA4, Pa5].sort
You can define the <=> method in your own class. Suppose that each painting has a price attribute that represents its cost:

def <=> (other_painting)
Self.price <=> Other_painting.price
End
Now the order of a set of paintings is sorted according to its price.

Comparable module

If <=> is defined in a class, an instance of the class can be sorted in an array or other enumerable object.
If you don't define <=>, you can sort the objects, but you need to put them in an array and provide a block of code that tells the array what you're going to sort by.
If you define the <=> in the class, you also mix the comparable. You get the ability to sort in an array, and your object can perform all the comparison operations.
Defining sorting criteria in code blocks

We have defined painting#<=>, sorted the price of a painting, and now you want to force the use of chronological order to do this:

Year_sort = [PA1, PA2, Pa3, PA4, Pa5].sort do |a,b|
A.year <=> B.year
End
Two kinds of things do not know how to compare each other, such as integers and strings, if you "2" <=> 4, will be an error, you can do this first:

>> ["2", 1,5, "3", 4, "6"].sort {|a,b| a.to_i <=> b.to_i}
=> [1, "2", "3", 4, 5, "6"]
Sort_by

Sort and sort_by are examples of enumerable methods. The difference is that Sort_by has to provide it with a block of code, and you just have to tell it how to treat the items in the collection:

>> ["2", 1,5, "3", 4, "6"].sort_by {|a| a.to_i}
=> [1, "2", "3", 4, 5, "6"]
Enumerator and the next dimension's enumeration

The state is better, I am not suitable for getting up early:
Enumerators (enumerator) are similar to iterators (iterator), but they are not the same thing. An iterator is a method that yield one or more values to a block of code. An enumerator is an object, not a method. Essentially, an enumerator is a simple, enumerable object. It has each method, it uses the enumerable module, defines the commonly used method, for example: Select,inject,map and so on.

The enumerator is not a container object, and its each function is not innate, you have to tell it how each, so the enumerator can do its own to understand how to map,find,take,drop and so on.

Two ways to create an enumerator

Call Enumerator.new and give it a block of code that contains each logic.
Attaches the enumerator to the iterator of the other object.
To create an enumerator with a code block

E = enumerator.new do |y|
Y << 1
Y << 2
Y << 3
End
Y is a yielder, which is an instance of Enumerator::yielder that is automatically passed into your code block. In the example above, when the enumerator calls each, it first yield 1, then 2, then 3. The << method tells Yielder what to yield.

Use e:

>> e.to_a
=> [1, 2, 3]
>> E.map {|x| x * 10}
=> [10, 20, 30]
>> e.select {|x| x > 1}
=> [2, 3]
>> E.take (2)
=> [1, 2]
Rewrite e:

E = enumerator.new do |y|
(1..3). Each {|i| y << i}
End
E's behavior is the same as before.

Do not yield directly in the code block, you cannot:

E = enumerator.new Do
Yield 1
Yield 2
Yield 3
End
Trace the execution of the method:

E = enumerator.new do |y|
Puts "Starting up the block!"
(1..3). Each {|i| y << i}
Puts "exiting the block!"
End
P E.to_a
P E.select {|x| x > 2}
Output:

Starting up the block!
Exiting the block!
[1, 2, 3]
Starting up the block!
Exiting the block!
[3]
Try again:

A = [1,2,3,4,5]
E = enumerator.new do |y|
Total = 0
Until A.empty?
Total + = A.pop
Y << Total
End
End
Use:

>> E.take (2)
=> [5, 9]
>> A
=> [1, 2, 3]
>> e.to_a
=> [3, 5, 6]
>> A
=> []
Attaching an enumerator to another object

Attach the enumerator to an iterator on the other object. This iterator is typically each, but any method that can yield one or more values can be used. This gives the main functionality that the enumerator can iterate over. When it needs to yied something, it triggers the object it attaches to to yield.

Using this method to create an enumerator, you can invoke the Enum_for (also named: To_enum) method on the object, and the first parameter of the method can set the name of the method to which each method of the enumerator is to be attached. The default value of this parameter is: each, you can also change to other methods, such as:

names =%w{Matt Damon Scarlett Johansson}
E = names.enum_for (: Select)
The parameter of the method is set to: SELECT, meaning that the enumerator is bound to the names this array's Select method. That is, each method of the enumerator is used like the array's Select method:

>> E.each {|n| n.include? (" S ")}
=> ["Johansson"]
Additional parameters for Enum_for:

>> names =%w{Matt Damon Scarlett Johansson}
=> ["Matt", "Damon", "Scarlett", "Johansson"]
>> e = names.enum_for (: Inject, "names:")
=> #<enumerator: ["Matt", "Damon", "Scarlett", "Johansson"]:inject ("Names:") >
>> E.each {|string, name| string << "#{name}"}
=> "Names:matt ... Damon ... Scarlett ... Johansson ... "
Two forms, the effect is the same:

Enumerator.new (obj, method_name, arg1, arg2 ...)
Obj.enum_for (Method_name, arg1, arg2 ...)
An implicit enumerator

An iterator is a method that can provide one or more values to a code block. When an iterator is invoked, most iterators return an enumerator if it is not provided with a block of code.

>> str = ' Hello '
=> "Hello"
>> Str.each_byte {|b| puts B}
104
101
108
108
111
=> "Hello"
If so:

>> Str.each_byte
=> #<enumerator: "Hello":each_byte>
The equivalent is:

>> str.enum_for (: each_byte)
The semantics and use of enumerators

What happens when each is called. Use enumerators to better control iterations.

Each method that uses the enumerator

Each method of the enumerator hooks up with the method of another object, and this method is likely to be a method other than each. If you use it directly, it will be like other methods, including the value it returns.

This may produce some seemingly bizarre results, calling each to return filtered, sorted, or mapped collections. Look at an example:

>> array =%w{cat Dog Rabbit}
=> ["Cat", "dog", "Rabbit"]
>> e = Array.map
=> #<enumerator: ["Cat", "dog", "Rabbit"]:map>
>> E.each {|animal| animal.capitalize}
=> ["Cat", "Dog", "Rabbit"]
The enumerator is not the same object as that array. About each is what it means to have its own ideas. However, by connecting an enumerator to the map method of an array, using each, it returns a value that is an array of mapping. Typically, each iteration is an array, primarily for its side effects and the recipient (an array) that will return it.

But An enumerator's each serves as a kind ofconduit to the "method" from which it pulls its values and behaves the same way In the matter of return value.
However, each function of an enumerator is used as a conduit to a method, pulling its value and behavior, and returning a value.

Not covered phenomenon

If an object defines each method and contains enumerable, its instance automatically gets map,select,inject and other enumerable methods. All of these methods are defined according to each.

But sometimes, the class has used its own method to cover up the method in the enumerable. such as Hash#select. The standard Select method in enumerable returns an array forever, but the select in the hash returns a hash:

>> h = {"Cat" => "Cats", "dog" => "dogs", "cow" => "cattle"}
=> {"Cat" => "Cats", "dog" => "dogs", "cow" => "cattle"}
>> h.select {|k,v| k =~/c/}
=> {"Cat" => "cats", "cow" => "ox"}
If we hang the enumerator over the Select method, it will give us a single method like select:

>> e = h.enum_for (: Select)
=> #<enumerator: {"Cat" => "Cats", "dog" => "dogs", "cow" => "cattle"}:select>
>> E.each {|k,v| k =~/c/}
=> {"Cat" => "cats", "cow" => "ox"}
What if we hang the enumerator over each method of the hash?

>> e = H.to_enum
=> #<enumerator: {"Cat" => "Cats", "dog" => "dogs", "cow" => "cattle"}:each>
Call Hash#each, take the code block, and return the Hash. Each of the enumerator is the same, because it is just a front-end to each of the hashes. The following code block is blank because it only cares about its return value:

>> H.each {}
=> {"Cat" => "Cats", "dog" => "dogs", "cow" => "cattle"}
>> E.each {}
=> {"Cat" => "Cats", "dog" => "dogs", "cow" => "cattle"}
What happens if we use this each to execute a select control?

>> e.select {|k,v| k =~/c/}
=> [["Cat", "feline"], ["Cow", "ox"]]
We'll get an array, not a hash. If E.each hangs on the H.each, why is the value returned by E.select not linked to H.select? The key to the problem is that the Select method called above actually calls the select methods on the enumerator, not the select on the hash. The Select method on the enumerator is created based on each method of the enumerator. This select is Enumerable#select, which returns an array forever. The Hash#select returns a hash.

The enumerator has the ability to add enumerations to the hash, even if the hash can already be enumerated. A select that does not overwrite the enumerable#select,select is the enumerable#select,hash of the enumerator is not.

It is important to remember that the enumerator is not the same object as the one that inhaled the iteration object. Accessing the collection through an enumerator protects the collection object from being modified.

Protecting objects with enumerators

Suppose a method needs to use an array as its argument.

def give_me_an_array (Array)
If you give this method an array object, the method can modify the object:

Array << "new element"
If you want to protect the original array object, you can copy it and give the copy to this method. Or you can pass an enumerator to it:

Give_me_an_array (Array.to_enum)
Enumerators allow an iterative group, but it does not receive modifications, such as when you invoke << on it. That is, the enumerator can be used as a protection mechanism for the collection object, which allows iterations to be tested, and the elements in the collection are checked, but does not allow you to perform destructive operations.

The enumerator can better control the iterations

Let's do an experiment:

>> pets =%w{Dog Cat}
=> ["Dog", "cat"]
>> e = Pets.to_enum
=> #<enumerator: ["Dog", "Cat"]:each>
>> puts E.next
Dog
=> Nil
>> puts E.next
Cat
=> Nil
>> puts E.next
Stopiteration:iteration reached an end
From (IRB): 105:in ' Next '
From (IRB): 105
From/usr/local/bin/irb:11:in ' <main> '
>> E.rewind
=> #<enumerator: ["Dog", "Cat"]:each>
>> puts E.next
Dog
=> Nil
An enumerator is an object that can maintain state. It remembers the location of the enumeration. An iterator is a method that ends when the call completes. The iterator has no status. An enumerator is an enumerable object.

Ability to add enumerations with enumerators

You can use enumerators to add enumeration capabilities to objects that do not have the ability to enumerate. If you hook each method of the enumerator to any iterator, you can use the enumerator to do enumeration operations on the object's own iterator, regardless of whether the object itself can be enumerated.

If you hang the enumerator over the String#bytes method, you add an enumeration capability to a string object.

The following class does not have a mixed enumerable, but it has an iterator method:

Module Music
Class Scale
NOTES =%w{C C # D d# E F F # G a a# B}

def play
Notes.each {|note| yield note}
End
End
End
Perform:

Scale = Music::scale.new
Scale.play {|note| puts "Next note is #{note}"}
Results:

Next is C
Next is C #
Next is D
Music::scale does not have a mixed enumerable and does not define each method, so:

Scale.map {|note| Note.upcase}
The result will be:

Nomethoderror:unknown method ' map ' for #<music::scale:0x3b0aec>
To allow scale to have all the enumeration functions, you have to mix the enumerable and change the name of play to each. You can also hang an enumerator over the scale.

Creates an enumerator over a scale object, tied to the play method:

enum = Scale.enum_for (:p lay)
The enum enumerator has each method, and this method does the same iteration as the scale play method. The difference is that the enumerator is an enumeration object that has map,select,inject these methods from the enumerable. If you use an enumerator, you can perform enumeration operations on objects that cannot be enumerated at all:

P Enum.map {|note| note.upcase}
P Enum.select {|note| note.include? (' F ')}
First line output:

["C", "C #", "D", "d#", "E", "F", "F", "G", "A", "a#", "B"]
Second line output:

["F", "F #"]
The enumerator uses each method on the object that it attaches to as the underlying method, which is used by the enumerated toolkit.

An enumerator is an object that can be enumerated, and its each method is somewhat like a siphon, extracting values from iterators defined on other objects.
The method chain of the enumerator

Method chains are common in Ruby.

>> names
=> ["Matt", "Damon", "Scarlett", "Johansson"]

>> names.select {|n| n[0] < "M"}.map (&:upcase). Join (",")
=> "DAMON, Johansson"
A method chain typically creates a new object at each node in the chain.

In the example above, names is an array of strings, and Ruby creates two extra arrays, one is created by SELECT, one is created by map, and a join creates a string. In some cases, the enumerator can mitigate the problem of creating intermediate objects.

Saving Intermediate objects

There are many methods in the enumerable module that return an enumerator when you do not provide code blocks to call them. There is no reason to link other methods directly with enumerators. For example Names.each.inject and Names.inject, similar and names.map.select and you directly use Names.select same. The map enumerator does not know what the map is, that is, it can only delegate the value of the original array to the method chain.

But there are situations where you can call a method by chain:

>> names
=> ["Matt", "Damon", "Scarlett", "Johansson"]

>> names.select {|n| n[0] < "M"}.map (&:upcase). Join (",")
=> "DAMON, Johansson"
With_index

>> (' A ' ... ') Z '). Map.with_index {|letter, i| [Letter, I]}

=> [["A", 0], ["B", 1], ["C", 2], ["D", 3], ["E", 4], ["F", 5], ["G", 6], ["H", 7], ["I", 8], ["J", 9], ["K",], ["L" , one], ["M", "," ["N", "], [" O ","], ["P", ["Q",], ["R",], ["s",], ["T",], ["U",], ["V",], ["W", [x], ["Y",], ["Z", 25]]
Lazy Enumerator

The lazy enumerator can have a large collection of selected enumerations.

Try this:

(1..float::infinity). Select {|n| n% 3 = 0}.first (10)
Will always run ... select will not end.

At this point, you can create a lazy enumerator:

>> (1..float::infinity). Lazy
=> #<enumerator::lazy:1..infinity>
And then this again:

>> (1..float::infinity). lazy.select {|n| n% 3 = 0}
=> #<enumerator::lazy: #<enumerator::lazy:1..infinity>:select>
>> (1..float::infinity). lazy.select {|n| n% 3 = 0}.first (10)
=> [3, 6, 9, 12, 15, 18, 21, 24, 27, 30]
Another method:

>> (1..float::infinity). lazy.select {|n| n% 3 = 0}
=> #<enumerator::lazy: #<enumerator::lazy:1..infinity>:select>
>> (1..float::infinity). lazy.select {|n| n% 3 = 0}.first (10)
=> [3, 6, 9, 12, 15, 18, 21, 24, 27, 30]
Fizzbuzz

If the number can be divisible by 15, the output "Fizzbuzz"
Otherwise, if the number may be divisible by 3, the output "fizz"
Otherwise, if the number is divisible by 5, the output "Buzz"
Or we're going to output this number.
def fb_calc (i)
Case 0
When I% 15
"Fizzbuzz"
When I% 3
"Fizz"
When I% 5
"Buzz"
Else
i.to_s
End
End

def FB (N)
(1..float::infinity). Lazy.map {|i| Fb_calc (i)}.first (n)
End
Try this:

P FB (15)
Will output:

["1", "2", "Fizz", "4", "Buzz", "Fizz", "7", "8", "Fizz", "Buzz", "one", "Fizz", "," "," "Fizzbuzz"]

Related Article

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.