# Each When we met the `Array` class, we noted that most of what we do as developers is manage _lists of things_ — photos, likes, followers, reviews, listings, messages, rides, events, concerts, projects, etc etc etc — and `Array` is the data structure that we'll most commonly use to contain these lists. Therefore, the most common reason we'll have to write loops is to **visit each element in an `Array` and do something interesting with it** — for example, display the element to the user with some formatting around it. - Quick quiz. Which of these would result in an `Array` class object in the variable `a`? Select all that apply, and use the empty runnable code block below if you want for testing. - `a = ()` - No, parentheses are used after a method to list the arguments to the method - `a = Array` - No, what method do we need to call _on_ `Array` to create a new one? - `a = []` - Yes! Thanks to some syntactic sugar - `a.new = Array` - No, the method should be on the right side of the assignment operator - `a = Array.new` - Yes! - `a = "ruby".split("")` - Yes! The `""` argument to `split` will separate each character - `a = [1, 2, 3]` - Yes! {: .choose_all #arrays title="Array review" points="4" answer="[3,5,6,7]" } ```ruby # test your knowledge ``` {: .codeblock #testing_arrays title="Test runnable code block"} ## Iterating over arrays with Integer's times method Let's try transforming the words in an `Array` using what we've learned so far about loops. This program takes a list of words and prints each word in three forms: ```ruby words = ["apple", "banana", "orange"] number_of_words = words.count number_of_words.times do |the_index| pp words.at(the_index).capitalize pp words.at(the_index).reverse pp words.at(the_index).upcase end ``` {: .codeblock #three_forms_times title="Three forms with times" points="1"} You see that I chose to use `.times` for this job. - On Line 2, we count the length of the array. - On Line 4, we use that length with the `.times` method to kick off a loop with the correct number of iterations. - Within the block, we use the block variable (which we named `the_index`) to access the correct element within the array. - We printed the array element capitalized, reversed, and then upcased. Using `.times` to iterate over an `Array` is not bad at all, especially because `.times`'s block variable starts at `0`, just like array indexing does. Using `.times` is certainly cleaner than using `while`, where we would have to create and increment a counter variable ourselves, and then write a condition to make sure that the loop stops after the correct number of iterations (the length of the array). ## Array's each method But we can do even better than using `Integer`'s `.times` (or `.step`) method to iterate over an `Array`. There's a method that you can call directly on the `Array` itself called `.each`. Compare the code below to the previous runnable code block and try to find the differences: ```ruby words = ["apple", "banana", "orange"] words.each do |the_word| pp the_word.capitalize pp the_word.reverse pp the_word.upcase end ``` {: .codeblock #three_forms_each title="Three forms with each" points="1"} Click "Run" and verify that both programs do the same thing. Nice! `.each` has two clear benefits over using `.times`: - We don't need to count the length of the array; `.each` does it for us and will take care of looping for the correct number of iterations. - The block variable, rather than containing an integer that we can use to access the correct element, will contain **the element itself**. So now when we name the block variable, we should choose a name that reflects what each element in the list is. `.each` will, behind the scenes, pull the correct element out of the array before each iteration begins and assign it to that block variable. Then, **we just use that variable directly**, and we don't have to worry about accessing the array with `.at`. The hardest part, I think, is getting your head around the block variable; in this case, `|the_word|`. It takes some practice. Try to remember that it's just a name that _we make up_, and `.each` takes care of putting each element in that variable for us behind the scenes. I could have called it `zebra` if I wanted to; there's nothing special about the name of the variable — in particular, it doesn't have to match the name of the variable containing the array (`words`). Just try to pick something descriptive of an individual element in the list. ## Practice using each Looping over lists of things with `.each` is _very_ important for us. Let's get some practice writing small programs using `.each` and `|block_variables|` in the next three graded code blocks. ### Spell this word Write a program that, given a randomly `sample`d `word` from the list, spells it out letter-by-letter, with capital letters. For example, if the `word = "Georgia"`, the output should be: ``` "G" "E" "O" "R" "G" "I" "A" ``` Hint: recall, `.split("")` will separate a `String` into an `Array` of characters, so you can write `word.split("").each ...` to start your program. ```ruby word = ["Ruby", "application", "zebra"].sample # write your program here ``` {: .codeblock #spelling title="Spelling" readonly_lines="[1]" points="1"} ```ruby describe "Spelling" do it "should print ''S' 'U' 'P' 'E' 'R'' if the input is 'Super'" do replace_read_only_value(variable_name: "word", new_value: "Super") output = run_codeblock expect(output).to fuzzy_match("S U P E R") end end ``` {: .codeblock-test #spelling_test_1 for="spelling" title="Spelling should print ''S' 'U' 'P' 'E' 'R'' if the input is 'Super'" points="1"} ### Even word Now write a program that, given the `list_of_words`, only prints the words that have an even number of characters. For example, if the list was `["mountain", "pink", "vines"]`, the output should be: ``` "mountain" "pink" ``` Hint: remember you can nest `if`-`else` conditionals inside of loops. ```ruby list_of_words = ["zebra", "giraffe", "monkey", "salmon"] # write your program here ``` {: .codeblock #even_words title="Even words" readonly_lines="[1]" points="1"} ```ruby describe "Even words" do it "should print 'monkey salmon'" do failure_if_literally_printing("monkey") failure_if_literally_printing("salmon") output = run_codeblock expect(output).to fuzzy_match("monkey salmon") end end ``` {: .codeblock-test #even_words_test_1 for="even_words" title="Even words should print 'monkey salmon'" points="1"} ```ruby describe "Even words" do it "should print nothing if the input is ['odd', 'numbers', 'squad']" do replace_read_only_value(variable_name: "list_of_words", new_value: ["odd", "numbers", "squad"]) output = run_codeblock expect(output).to match("") end end ``` {: .codeblock-test #even_words_test_2 for="even_words" title="Even words should print nothing if the input is ['odd', 'numbers', 'squad']" points="1"} ### Letter count Finally, use `.each` to write a program that, given a randomly `sample`d `word` from the list, prints each letter in the word, and the number of times that letter appears. For example, if `word = "loop"`, the output of your program should be: ``` "l appears 1 times" "o appears 2 times" "o appears 2 times" "p appears 1 times" ``` Hint: recall, `.split("")` will separate a `String` into an `Array` of characters, and `.count()` will count the number of occurrences of a given character in a `String`. ```ruby word = ["photo", "like", "commenter"].sample # write your program here ``` {: .codeblock #letter_count title="Letter count" readonly_lines="[1]" points="1"} ```ruby describe "Letter count" do it "should print the correct output for 'loop'" do replace_read_only_value(variable_name: "word", new_value: "loop") output = run_codeblock expect(output).to fuzzy_match("l appears 1 times o appears 2 times o appears 2 times p appears 1 times") end end ``` {: .codeblock-test #letter_count_test_1 for="letter_count" title="Letter count should print the correct output for 'loop'" points="1"} ```ruby describe "Letter count" do it "should print the correct output for 'levee'" do replace_read_only_value(variable_name: "word", new_value: "levee") output = run_codeblock expect(output).to fuzzy_match("l appears 1 times e appears 3 times v appears 1 times e appears 3 times e appears 3 times") end end ``` {: .codeblock-test #letter_count_test_2 for="letter_count" title="Letter count should print the correct output for 'levee'" points="1"} ## Sneak peek Just a sneak peek as to why `.each` is so important to get comfortable with: soon, you'll be embedding Ruby loops in your web applications to create dynamic, data-driven pages with code that looks something like this: ```erb <% newsfeed_photos.each do |the_photo| %>

<%= the_photo.caption %>

<% end %> ``` Code like this is what drives the dozens of dynamic applications you interact with on a daily basis — we pull a list of records from a database table, then we loop over them, and then we format each one using some _markup language_ (in this case HTML for the browser, but it could be XML for native apps, etc). ## Conclusion That's it for `.each` and loops. It's time to meet a very important data structure class that we will be seeing a lot: `Hash`. - Approximately how long (in minutes) did this lesson take you to complete? {: .free_text_number #time_taken title="Time taken" points="1" answer="any" }