All language subtitles for pragstudio-ruby-18-iterators (Transcribed on 27-Apr-2023 20-38-34)

af Afrikaans
ak Akan
sq Albanian
am Amharic
ar Arabic
hy Armenian
az Azerbaijani
eu Basque
be Belarusian
bem Bemba
bn Bengali
bh Bihari
bs Bosnian
br Breton
bg Bulgarian
km Cambodian
ca Catalan
ceb Cebuano
chr Cherokee
ny Chichewa
zh-CN Chinese (Simplified) Download
zh-TW Chinese (Traditional)
co Corsican
hr Croatian
cs Czech
da Danish
nl Dutch
en English
eo Esperanto
et Estonian
ee Ewe
fo Faroese
tl Filipino
fi Finnish
fr French
fy Frisian
gaa Ga
gl Galician
ka Georgian
de German
el Greek
gn Guarani
gu Gujarati
ht Haitian Creole
ha Hausa
haw Hawaiian
iw Hebrew
hi Hindi
hmn Hmong
hu Hungarian
is Icelandic
ig Igbo
id Indonesian
ia Interlingua
ga Irish
it Italian
ja Japanese
jw Javanese
kn Kannada
kk Kazakh
rw Kinyarwanda
rn Kirundi
kg Kongo
ko Korean
kri Krio (Sierra Leone)
ku Kurdish
ckb Kurdish (Soranî)
ky Kyrgyz
lo Laothian
la Latin
lv Latvian
ln Lingala
lt Lithuanian
loz Lozi
lg Luganda
ach Luo
lb Luxembourgish
mk Macedonian
mg Malagasy
ms Malay
ml Malayalam
mt Maltese
mi Maori
mr Marathi
mfe Mauritian Creole
mo Moldavian
mn Mongolian
my Myanmar (Burmese)
sr-ME Montenegrin
ne Nepali
pcm Nigerian Pidgin
nso Northern Sotho
no Norwegian
nn Norwegian (Nynorsk)
oc Occitan
or Oriya
om Oromo
ps Pashto
fa Persian
pl Polish
pt-BR Portuguese (Brazil)
pt Portuguese (Portugal)
pa Punjabi
qu Quechua
ro Romanian
rm Romansh
nyn Runyakitara
ru Russian
sm Samoan
gd Scots Gaelic
sr Serbian
sh Serbo-Croatian
st Sesotho
tn Setswana
crs Seychellois Creole
sn Shona
sd Sindhi
si Sinhalese
sk Slovak
sl Slovenian
so Somali
es Spanish
es-419 Spanish (Latin American)
su Sundanese
sw Swahili
sv Swedish
tg Tajik
ta Tamil
tt Tatar
te Telugu
th Thai
ti Tigrinya
to Tonga
lua Tshiluba
tum Tumbuka
tr Turkish
tk Turkmen
tw Twi
ug Uighur
uk Ukrainian
ur Urdu
uz Uzbek
vi Vietnamese
cy Welsh
wo Wolof
xh Xhosa
yi Yiddish
yo Yoruba
zu Zulu

Original subtitles

So we've already seen some built-in iterators, like each, times, and up to, and folks sometimes

think those are the only iterators you can use.

But it turns out you can actually write your own iterator methods.

So let's look at writing a couple basic iterators ourselves.

So let's suppose we wanted to write an iterator method called once, and we want to pass it

a block, or associate a block with that method call, and the block's just going to say,

running your block, just like that.

How would we implement this method?

Well, to find the method, it's just a normal method.

Inside of that method, to pass control over to the block, we call yield.

So before we do that, I'm just going to print out before yield, and then after it, I'm going

to print out after yield.

And let's run it and see what happens.

So it prints before yield, then it prints running your block, then it prints after yield.

So what happened was we ran the method once.

It ran its first statement here, before yield, then yield, pass control over to this block,

and it printed running your block.

Then the block exited, it was done.

So then control passes back into the method, it finishes by printing after yield.

Let's say we want a different iterator.

Maybe we want the iterator to be called twice.

We want to yield to the block twice.

Well, we can just call yield multiple times inside of the method, change this over to

twice.

Now, if we run it, sure enough, we get before yield, it runs the block twice, and then we

get after yield.

How about we want the iterator to be called three times, but in this case, we want to

do something slightly different.

We want the iterator to pass the current iteration, like we've seen before with other iterator

methods.

So we want it to pass us the current number, and then inside of there, we're just going

to print out the number that it gives us.

Number like that.

So the method's going to be called three times, and then instead of before yield, I'm just

going to print here.

I'm going to say ready.

We're going to yield.

Now, any parameters that we pass to yield are going to get passed off to the associated

block.

So we could call yield and pass in the number one, right?

And then I'm going to print, put as set, and then we could call yield again.

Yield is a method here.

I can use the actual parentheses for two, or I could just say yield two because parentheses

in Ruby are optional.

So then I can say yield two, this would be go, and then I could say yield three, just

like that.

So now if we run that, we see it yielded to our block three times, and it gave it the

numbers one, two, and three.

Now that's pretty cool.

Let's look at that in slow motion.

We call the three times method with an associated block.

The method begins to execute, the first thing it does is print ready.

Then the method calls yield, passing the number one.

At that point, the associated block is invoked.

The value we pass to yield, the number one, is assigned to the block parameter number.

The block prints one.

Then the block returns control back over to the method.

The method prints set.

Then it yields to the block again, passing in two, and the block prints two.

Then we go back to the method, it prints go, and then we yield to the block a third time,

passing three, and the block prints three.

And then we come back to the method, and it ends.

So the cool thing about these iterator methods is they decouple the actual looping from what

happens during each iteration.

Here, let me show you.

So we could change this inside of here.

Instead of just printing out the number, we could say maybe it's the number times two,

for example.

If we run this code, the iterator does exactly the same thing, but when it turns control

over to our block, now we're multiplying the number by two.

Or maybe we want to just take number times number, one, four, and nine.

So our iterator method stays the same.

We don't have to change it at all, but we can change what happens during each iteration

simply by changing what's inside of the block.

Now blocks can also return a value.

So the last expression that's evaluated by the block will be returned as the value of

the yield.

Let's look at that.

I'm just going to clean this code up.

I don't want to do that.

And I'm going to write a new iterator.

Let's call it compute.

Inside of that method, I'm going to yield, but then I want to print out the result of

calling yield.

So let's see what happens.

If we call compute, we're going to pass it a block, and I'm just going to return.

The block's just going to say hello like that.

So if I run it now, then I see that it prints hello.

Even though I'm not using a put s here, this string is getting returned by the block here,

and then the put s is then printing that string to the console.

So let's say we had multiple statements in here.

Maybe we had like 7, 3.14.

If I run this now, well, the result of that block is 3.14, and it gets printed because

it's the last expression that's evaluated inside of the block.

But what happens if we try to call the iterator method without a block?

Well, if we just take the block off of here and we call it, we get this method local jump

error.

Wow, that looks scary.

No block given to yield.

So if we've got a yield just like this, it expects there to be an associated block, and

it tries to call it.

But we can get around that a little bit by using a conditional.

We can say if block underscore given, that's a built-in Ruby method.

If a block is given, then go ahead and yield to it.

Else, we'll just print out something like does not compute.

So now if I run it, no blocks given, we get does not compute.

Otherwise, I can put a block in here.

Maybe the block just says the number 3.14, for example, and then the block runs.

So what happens when we combine iterator methods with blocks that return values?

Well, here's something kind of clever about Ruby.

I'm just going to clean up this file here, and let's start with something else.

Remember, let's just create an array.

Let's say it's 10 numbers, right?

And remember our old friend select.

We could call select on that array, and it gives us a value, and then we select out all

the ones that are even, for example.

So if we run that, we get all the even numbers.

And that select looks kind of special, but let's think about how we might actually implement

that in Ruby.

Let's define a method called mySelect, just to keep it separate from the select that's

built into array.

And it would take, let's say, an array as a parameter there.

So we're not going to put this on the array class.

We're just going to have our own method, mySelect, that takes an array.

How would we implement select?

Well, clearly, we want to be able to create an array and return it that just has the elements

that we've selected.

So let's just start with saying that the results is an empty array, and at the end, we want

to be able to return those results.

Then what we want to do is just loop through each of the elements in the array using a

built-in iterator.

It's going to give us each element in that array.

And now what we want to do is capture all the elements of that array that match some

criteria.

So we want to append to our results array that element that we're looping through, only

if the result of running some block says that we should include that element.

So what we can do is we can say, OK, go ahead and run the block, yield, and give the block

the element so it can decide whether it should include it or not.

Then we can just call our method.

We'll just use putS, mySelect.

We'll pass in our numbers array.

It's going to yield to a block.

So let's give it a block just like that.

It's also going to give us the element, in this case n.

The block looks just like it does with a regular select.

If I just take off the select up here, and we run this now, we get all the even numbers.

So that gives us some insight into how select, reject, partition, and some of these other

iterator methods we've used actually work.

So this is all kind of interesting, but what's a practical use of an iterator like this?

Well, I have an idea where this could be useful.In the game, you're currently printing this.

And it would be nice to be able to print each player's points on a per-treasure basis.

And in the same way, our playlist is currently printing something like this.

And we want to be able to print each movie's snacks on a per-snack basis.

So let's recap where things stand.

When a movie is played, a random snack is snagged from the snack bar.

In the movie object, we call 8 snack and then pass in the random snack object.

The movie then stores the snack's name and accumulated carbs in a hash.

So in this example, two popcorns were consumed for a total of 40 carbs, and one soda, or

pop, was consumed for 5 carbs.

We can then print out the grand total number of carbs consumed, 45 in this case.

Now we want to be able to print out each movie's snacks on a per-snack basis.

We don't want to expose the hash outside of the movie.

How it stores snacks is an implementation detail.

Instead, we'll write an each snack iterator method that hands out snack objects representing

what's in the hash.

Here's how we'll use that iterator method.

Each snack yields snack objects to an associated block.

So the first time through, the block will print 40 total popcorn carbs.

And then the second time through, it'll print 5 total soda carbs.

Yeah, and if we put this code in the printStats method of the playlist class, then we get

the output we're aiming for.

And the playlist class, which you can think of as a client to the movie class, will be

none the wiser about how snacks are stored in the movie.

So let's do that.

So we're over in our playlist class in this printStats method, and what we want to do

is right now we're just printing out the movie's grand total carbs.

And what we want to be able to do, the code we want to be able to write here is to take

the movie, this is the movie inside of this loop, and we want to be able to call an iterator

like each snack.

And then that iterator method should give us a snack object like that.

And then inside of the block, we want to be able to print out snack carbs total snack

name carbs.

Should be something like 15 total soda carbs, for example.

So the movie is going to vend out these snacks to us using this iterator method.

So let's go write that.

Go over to movie, and write our iterator.

It's going to be called each snack.

What's it going to do?

Well, we're going to take our snack carbs hash.

We're going to iterate through the keys and the values for it.

Let me set up my block here.

This is going to be the name.

This is going to be the carbs.

So remember, when we gave the snack object to the movie via the eight snack method, we

deconstructed it into name and carbs inside of our hash.

Now we want to put that back together again.

So we want to be able to yield an actual snack object.

So let's create a snack object.

Snack.new.

The name of the snack is the key of our hash, and the carbs of the snack is the value of

our hash, which came in in this second parameter here.

So we're just taking the key value pair out of the hash, and we're constructing a new

snack object.

Then we'll just yield that snack object over to the block.

We save that.

If we look back in our playlist method, we're expecting a snack object here, because we're

going to look at its carbs and its snack and its snack name.

So now we should be able to go over to flix.rb.

And if we run it and look at the bottom, now we've got our total carbs at the top.

And then for each movie, we've got a breakdown of the carbs for each particular snack, and

then the total at the bottom.

Now you're probably not going to write your own iterator method all that often, but in

certain situations, they come in really handy.

In this case, we made the movie class easier to use.

In the same way we can ask an array for all of its elements, we can ask a movie for all

of its snacks.

And in the exercise, you're going to do something very similar.

You're going to print out each player's points on a per-treasure basis.

Then when you come back, we'll look at taking some user input from the command line or the

console, and we'll also look at how to read and write to files.

We'll see you then.

You'll kind of be like...

I don't know how to fake laugh.

That's the problem.

It's hard.

It is really...

It would come out so cheesy.

I'd be like, haha!

Okay.

I could do that.

Well, I'll laugh at my own joke.

Should I do that, Matt?

No.

Can't find what you're looking for?
Get subtitles in any language from opensubtitles.com, and translate them here.