diff --git a/4_Arrays/1_Creating_Arrays/solution.rb b/4_Arrays/1_Creating_Arrays/solution.rb new file mode 100644 index 0000000..aedd9e3 --- /dev/null +++ b/4_Arrays/1_Creating_Arrays/solution.rb @@ -0,0 +1,3 @@ +# e.g.: +objects = [2.75, true, []] +question_marks = Array.new(3, '?') diff --git a/4_Arrays/1_Creating_Arrays/solution_spec.rb b/4_Arrays/1_Creating_Arrays/solution_spec.rb new file mode 100644 index 0000000..82abec6 --- /dev/null +++ b/4_Arrays/1_Creating_Arrays/solution_spec.rb @@ -0,0 +1,93 @@ +require 'rspec' +require 'rspec/expectations' +require 'code_breaker' + +VARIABLES = [:objects, :question_marks].freeze + +def code_lines + %q{[['solution::code']]} +end + +def statements + @statements ||= Array(CodeBreaker.parse(code_lines)) +end + +def assignment?(statement) + statement.is_a?(Hash) && statement.keys.first == :lvasgn +end + +def brackets_statement + @brackests_statement ||= statements.select do |statement| + assignment?(statement) && statement[:lvasgn].first == VARIABLES.first + end +end + +def new_statement + @new_statement ||= statements.select do |statement| + assignment?(statement) && statement[:lvasgn].first == VARIABLES.last + end +end + +def array_assigned?(variable) + !!defined?(variable) && variable.is_a?(Array) +end + +def array_defined_with_new?(variable, statement) + array_assigned?(variable) && + statement.first[:lvasgn][1][0..1] == [{ const: :Array }, :new] +end + +describe 'Your code' do + [['solution::code']] + + VARIABLES.each do |name| + it "defines a variable with name \"#{name}\"" do + expect(local_variables.include?(name)).to be true + end + + if local_variables.include?(name) + it "assigns an Array to the variable \"#{name}\"" do + expect(eval(name.to_s)).to be_an Array + end + end + end + + if (local_variables & VARIABLES).sort == VARIABLES.sort + describe 'assings an Array to "objects" which' do + it 'is created by using []' do + expect(array_assigned?(objects)).to be true + expect(brackets_statement.first[:lvasgn].last.keys.first).to eq :array + end + + if array_assigned?(objects) + before { @values = brackets_statement.first[:lvasgn].last[:array] } + + it 'holds a Float' do + expect(@values.include?(Float)).to be true + end + + it 'holds a Boolean' do + included = @values.include?(TrueClass) || @values.include?(FalseClass) + expect(included).to be true + end + + it 'holds an empty Array' do + empty_array = { array: [] } + expect(@values.include?(empty_array)).to be true + end + end + end + + describe 'assings an Array to "question_marks" which' do + it 'is created by using #new' do + expect(array_defined_with_new?(question_marks, new_statement)).to be true + end + + if array_defined_with_new?(question_marks, new_statement) + it 'holds three times "?"' do + expect(question_marks).to eq ['?'] * 3 + end + end + end + end +end diff --git a/4_Arrays/1_Creating_Arrays/task.md b/4_Arrays/1_Creating_Arrays/task.md new file mode 100644 index 0000000..a5b3e78 --- /dev/null +++ b/4_Arrays/1_Creating_Arrays/task.md @@ -0,0 +1,88 @@ +# Creating Arrays + +--- + +*You will learn:* +- what an Array is +- what you can store in an Array +- how to create Arrays + +--- + +An Array is a *collection of objects*. + +This collection is *ordered*, which means that each object in an Array has a fixed +place assigned, a so called *index*. +The index is defined by an integer starting with 0: The first object in the Array +has the index 0, the second has the index 1, etc. + +The index can be used to access the objects in an Array. You will learn more +about using the index in the next unit "Accessing elements". + +An Array can hold all kinds of Ruby objects, such as Strings, Numbers, Booleans, +other Arrays, etc. The objects in an Array don‘t need to be of the same type. +An Array can hold all kinds of different objects (e.g. Strings, and Numbers) at the same time. + +Let‘s create some Arrays! + +## Creating an Array with [] + +Arrays can be created in different ways. +The shortest is surrounding a comma-separated list of objects with square brackets: + +` [1, 'Mary', true]` *# => [1, "Mary", true]* + +An Array is a Ruby object itself. If you ask for an Array‘s class with the `class` method +you will get `Array`: + +` numbers = [1, 2, 3]` +` numbers.class` *# => Array* + +An Array is an object of type *Array*. + +Instead of using `[]` you can also use the the longer way and call the `[]` method +of the *Array* class: + +` Array[1, 2, 3]` *# => [1, 2, 3]* + +## Creating an Array with #new + +Besides using `[]`, you can create an Array by instantiating an Array with the `new` method. +The `new` method accepts two optional parameters: The number of elements, and the element itself. + +If you call `new` without any parameter it will create an empty Array: + +` Array.new` *# => []* + +If you only define the first parameter as an Integer, it will use this Integer to define +the length of the new Array and will assign *nil* for each element: + +` Array.new(2)` *# => [nil, nil]* + +If you pass an Array as first parameter it will return the defined Array: + +` Array.new([1, 2, 3])` *# => [1, 2, 3]* + +The actual interesting case is, if you pass both parameters. +It will create an array of the length given in the first parameter, with each element +being the second parameter. Here is an example: + +` Array.new(3, 4.5)` *# => [4.5, 4.5, 4.5]* +` Array.new(2, ['a', 'b'])` *# => [['a', 'b'], ['a', 'b']]* + + +Another way of creating an Array is calling `Array()` with a single parameter: + +` Array('banana')` *# => ["banana"]* + +This will create a new Array with only the given value and is the same as calling `['banana']`. + +--- + +Assign an Array to a variable *objects* by using the square brackets syntax for creating the Array. +The Array should have 3 elements: a Float, a Boolean, and an empty Array. + +Create an Array that holds 3 times the String *'?'* by using the `new` method. +Assign the Array to a variable *question_marks*. + +--- diff --git a/4_Arrays/2_Accessing_elements/solution.rb b/4_Arrays/2_Accessing_elements/solution.rb new file mode 100644 index 0000000..862d2c3 --- /dev/null +++ b/4_Arrays/2_Accessing_elements/solution.rb @@ -0,0 +1,7 @@ +# e.g.: +languages = ['Ruby', 'Elixir', 'Scala', 'Erlang', 'OCaml'] + +first = languages.first +last = languages.last + +some_languages = languages[1..3] diff --git a/4_Arrays/2_Accessing_elements/solution_spec.rb b/4_Arrays/2_Accessing_elements/solution_spec.rb new file mode 100644 index 0000000..b2158c6 --- /dev/null +++ b/4_Arrays/2_Accessing_elements/solution_spec.rb @@ -0,0 +1,44 @@ +require 'rspec' +require 'code_breaker' + +VARIABLES = [:languages, :first, :last, :some_languages].freeze + +describe 'Your code' do + [['solution::code']] + + VARIABLES.each do |name| + it "defines a variable with name \"#{name}\"" do + expect(local_variables.include?(name)).to be true + end + + if local_variables.include?(name) + if [:languages, :some_languages].include?(name) + it "assigns an Array to the variable \"#{name}\"" do + expect(eval(name.to_s)).to be_an_instance_of Array + end + elsif local_variables.include?(:languages) && name == :first + it "assigns the first language to the variable \"#{name}\"" do + expect(eval(name.to_s)).to eq languages.first + end + elsif local_variables.include?(:languages) && name == :last + it "assigns the last language to the variable \"#{name}\"" do + expect(eval(name.to_s)).to eq languages.last + end + end + + if name == :languages + it "assigns an Array to the variable \"#{name}\" with 5 String elements" do + values = Array.new(eval(name.to_s)) + expect(values.length).to eq 5 + values.each { |value| expect(value).to be_an_instance_of String } + end + end + + if local_variables.include?(:languages) && name == :some_languages + it "assigns an Array to the variable \"#{name}\" with 5 String elements" do + expect(eval(name.to_s)).to eq languages[1..3] + end + end + end + end +end diff --git a/4_Arrays/2_Accessing_elements/task.md b/4_Arrays/2_Accessing_elements/task.md new file mode 100644 index 0000000..2aa1ecb --- /dev/null +++ b/4_Arrays/2_Accessing_elements/task.md @@ -0,0 +1,81 @@ +# Accessing elements + +--- + +*You will learn:* +- how to get a certain element from an Array +- how to get subsets of elements from an Array + +--- + +Each element in an Array is associated with a fixed place – its *index*. +The index is an Integer by which you can access an element in the Array. + +The index 0 points to the first element, the index 1 to the second element, etc. +Negative indexes point to elements backwards from the last element. E.g. -1 points +to the last element, -2 points to the second last element, and so on. + +## Getting an element from an Array + +You can get the object from an Array at a certain index by using squared brackets: + +` numbers = [2, 4, 9]` *# defining an Array `numbers`* +` numbers[0]` *# => 2* +` numbers[1]` *# => 4* +` numbers[2]` *# => 9* +` numbers[-1]` *# => 9* + +If there is no element present for the given index you will get a *nil* value: + +` numbers[3]` *# => nil* + +`[]` is just an ordinary method that is defined for an instance of Array. + +Another way for getting a single element is using the alias method `at`: + +` numbers.at(0)` *# => 2* +` numbers.at(-1)` *# => 9* +` numbers.at(3)` *# => nil* + +There are two methods for getting special elements of an Array: `first` and `last`. +The method `first` – as you might have guessed – returns the first element +(at index 0), and `last` returns the last element (at index -1): + +` numbers.first` *# => 2* +` numbers.last` *# => 9* + +## Getting a subset of elements from an Array + +You can also pass two parameters to the `[]` method. This allows to select a subarray +by defining the index to start at and the number of elements you want to grab, e.g.: + +` numbers[1, 2]` *# => [4, 9]* + +returns two elements starting at index 1. If there are no elements for the given indexes +available, it returns *nil*: + +` numbers[10, 2]` *# => nil* + +Another way to select a subarray from an Array is to pass a *Range* of the wanted +indexes to `[]`: + +` numbers[1..2]` *# => [4, 9]* + +In case the elements are not available for the indexes it will again return *nil*: + +` numbers[5..10]` *# => nil* + +For more information about the `[]` method, see (ruby-doc core: Array#[]). + +--- + +Create an Array of 5 different programming languages (as Strings) and store it in +a *languages* variable. + +Define a variable *first* and assign the first programming language to it. + +Define a variable *last* and assign the last programming language to it. + +Store the three middle programming languages in a variable *some_languages*. + +--- diff --git a/4_Arrays/3_Adding_elements/solution.rb b/4_Arrays/3_Adding_elements/solution.rb new file mode 100644 index 0000000..f6f3821 --- /dev/null +++ b/4_Arrays/3_Adding_elements/solution.rb @@ -0,0 +1,7 @@ +baggage = ['shirt'] +baggage.unshift('glasses') +baggage.push('shoes') +baggage.insert(2, 'trousers', 'socks') + +# baggage +# => ["glasses", "shirt", "trousers", "socks", "shoes"] diff --git a/4_Arrays/3_Adding_elements/solution_spec.rb b/4_Arrays/3_Adding_elements/solution_spec.rb new file mode 100644 index 0000000..1538851 --- /dev/null +++ b/4_Arrays/3_Adding_elements/solution_spec.rb @@ -0,0 +1,41 @@ +require 'rspec' +require 'code_breaker' + +describe 'Your code' do + [['solution::code']] + + VARIABLE = :baggage + ITEMS = ['glasses', 'shirt', 'trousers', 'socks', 'shoes'] + + it 'defines a variable with name "baggage"' do + expect(local_variables.include?(VARIABLE)).to be true + end + + if local_variables.include?(VARIABLE) + before(:all) do + @statements = CodeBreaker.parse( %q{ [['solution::code']] }) + end + + it 'uses the unshift method to add "glasses"' do + unshift = [{ lvar: VARIABLE }, :unshift, String] + expect(@statements.include?(unshift)).to be true + end + + it 'uses the push or << method to add "shoes"' do + push = [{ lvar: VARIABLE }, :push, String] + arrows = [{ lvar: VARIABLE }, :<<, String] + + includes_code = @statements.include?(push) || @statements.include?(arrows) + expect(includes_code).to be true + end + + it 'uses the insert method to add "trousers" and "socks"' do + insert = [{ lvar: VARIABLE }, :insert, Fixnum, String, String] + expect(@statements.include?(insert)).to be true + end + + it 'changes your baggage to contain "glasses", "shirt", "trousers", "socks", & "shoes"' do + expect(eval(VARIABLE.to_s)).to eq ITEMS + end + end +end diff --git a/4_Arrays/3_Adding_elements/task.md b/4_Arrays/3_Adding_elements/task.md new file mode 100644 index 0000000..ca284b1 --- /dev/null +++ b/4_Arrays/3_Adding_elements/task.md @@ -0,0 +1,102 @@ +# Adding elements to Arrays + +--- + +*You will learn:* +- how to add elements to the end of an Array +- how to add elements to the beginning of an Array +- how to add elements at a specific index to an Array + +--- + +If you deal with an Array you will hardly just take the Array as is, but you likely want +to process and modify it or build new Arrays out of it. + +This unit will look into different ways of adding elements to an Array. + +## Adding elements to the end of an Array + +An Array object has several methods for adding elements. +If you want to add a *single* element to the end you can use the `<<` method: + +` numbers = [1, 2, 3]` +` numbers << 4` *# => [1, 2, 3, 4]* + +You could also write `numbers.<<(4)`, so the missing *.* and *()* are just a bit of +syntactic sugar. + +A similiar method for adding an element to the end of an Array is `push`: + +` chars = ['a', 'b']` +` chars.push('c')` *# => ['a', 'b', 'c']* + +The difference is, that `push` accepts multiple arguments, so that you can add as +many elements as you want in a single call: + +` chars.push('d', 'e', 'f')` *# => ['a', 'b', 'c', 'd', 'e', 'f']* + +Both `<<` and `push` will modify the given Array directly. If you check the values of +the variables above after calling the `<<` or `push` methods they will contain the +added values: + +` numbers` *# => [1, 2, 3, 4] * +` chars` *# => ['a', 'b', 'c', 'd', 'e', 'f']* + +If you want to build a new Array from an existing one by adding elements, the `+` method +will help you to combine two Arrays: + +` numbers = [1, 2]` + +` more_numbers = numbers + [3]` *# => [1, 2, 3]* +` even_more_numbers = numbers + [-1, -2]` *# => [1, 2, -1, -2]* + +The original Array will stay the same: + +` numbers` *# => [1, 2]* + +## Adding elements to the beginning of an Array + +If you want to add elements to the beginning of an Array instead, you can use the +`unshift` method which takes one or more elements to add as arguments: + +` numbers = [1, 2]` +` numbers.unshift(0)` *# => [0, 1, 2]* +` numbers.unshift(-2, -1)` *# => [-2, -1, 0, 1, 2]* + +Similar to `push`, the `unshift` method will modify the original Array. + +## Addding elements at a certain index + +If adding an element to the end or the beginning of an Array is not what you want, +then there is an `insert` method, that allows you to insert one or more elements +at a defined position: + +` vegetables = ['potato', 'pepper']` +` vegetables.insert(1, 'cucumber', 'cauliflower')` + +The first argument is the index where to insert the first element (keep in mind, that +the indexing starts at 0, so *1* means: “Insert before the second element”). + +Like `<<` and `push`, `insert` also modifies the original Array, so that *vegetables* holds +all the values now: + +` vegetables` *# => ['potato', 'cucumber', 'cauliflower', 'pepper'] + +Now that you have learned various methods for adding elements to an Array, +let’s summarize them again: + +` <<` *adds element at end modifies the original Array* +` push` *adds elements at end modifies the original Array* +` +` *adds elements at end creates a new Array* +` unshift` *adds elements at beginning modifies the original Array* +` insert` *adds elements at given index modifies the original Array* + +--- + +Prepare a case with some things for a trip: + +Create a variable *baggage* holding an Array with one element *"shirt"*. +Add a pair of *"glasses"* before the shirt and some *"shoes"* after the shirt. +Then add another *"trousers"* and a pair of *"socks"* before the shoes. + +--- diff --git a/4_Arrays/4_Removing_elements/solution.rb b/4_Arrays/4_Removing_elements/solution.rb new file mode 100644 index 0000000..edb3f5a --- /dev/null +++ b/4_Arrays/4_Removing_elements/solution.rb @@ -0,0 +1,8 @@ +baggage = ['shoes', 'underwear', 'socks', 'kettle', 'glasses', 'shirt', 'wallet'] + +baggage.shift +baggage.delete('kettle') +baggage.pop + +# baggage +# => ["underwear", "socks", "glasses", "shirt"] diff --git a/4_Arrays/4_Removing_elements/solution_spec.rb b/4_Arrays/4_Removing_elements/solution_spec.rb new file mode 100644 index 0000000..c40ca1b --- /dev/null +++ b/4_Arrays/4_Removing_elements/solution_spec.rb @@ -0,0 +1,38 @@ +require 'rspec' +require 'code_breaker' + +describe 'Your code' do + [['solution::code']] + + VARIABLE = :baggage + ITEMS = ['shoes', 'underwear', 'socks', 'kettle', 'glasses', 'shirt', 'wallet'] + + it 'defines a variable with name "baggage"' do + expect(local_variables.include?(VARIABLE)).to be true + end + + if local_variables.include?(VARIABLE) + before(:all) do + @statements = CodeBreaker.parse(%q{ [['solution::code']] }) + end + + it 'uses the shift method to remove "shoes"' do + shift = [{ lvar: VARIABLE }, :shift] + expect(@statements.include?(shift)).to be true + end + + it 'uses the delete method to remove the "kettle"' do + delete = [{ lvar: VARIABLE }, :delete, String] + expect(@statements.include?(delete)).to be true + end + + it 'uses the pop method to remove the "wallet"' do + pop = [{ lvar: VARIABLE }, :pop] + expect(@statements.include?(pop)).to be true + end + + it 'changes your baggage to only contain "underwear", "socks", "glasses", & "shirt"' do + expect(eval(VARIABLE.to_s)).to eq ['underwear', 'socks', 'glasses', 'shirt'] + end + end +end diff --git a/4_Arrays/4_Removing_elements/task.md b/4_Arrays/4_Removing_elements/task.md new file mode 100644 index 0000000..87b85d9 --- /dev/null +++ b/4_Arrays/4_Removing_elements/task.md @@ -0,0 +1,129 @@ +# Removing elements from Arrays + +--- + +*You will learn:* +- how to remove elements from the end of an Array +- how to remove elements from the beginning of an Array +- how to remove elements from an Array after a specific index +- how to remove a specific element + +--- + +Once you have created an Array, there might be the case that you don’t want to keep +all of the Array’s elements. This is where some methods for removing elements come +in handy. + +This unit will look into different ways of removing elements from an Array. + +## Removing elements from the end of an Array + +For removing one ore more elements from the end of an Array you can use the `pop` +method. The `pop` method modifies the orginal Array and returns the removed elements. +You can pass the number of elements to remove as argument: + +` numbers = [1, 2, 3, 4]` +` numbers.pop(2)` *# => [3, 4]* +` numbers` *# => [1, 2]* + +If you don’t pass the number of elements it will delete one element by default: + +` numbers = [5, 6, 7, 8]` +` numbers.pop` *# => 8* +` numbers` *# => [5, 6, 7]* + +Note that, if you remove multiple elements, `pop` will return an Array with the removed +elements. If you just remove the last element it will return this element. + +If you try to pop an element from an empty Array, there’s no element left to remove +and it will return *nil*: + +` [].pop` *# => nil* + +## Removing elements from the beginning of an Array + +For removing elements from the beginning of an Array you can use the `shift` method. +It takes an optional argument that specifies the number of elements to remove: + +` numbers = [0, 1, 2, 3]` +` numbers.shift(3)` *# => [2, 3]* +` numbers` *# => [0, 1]* + +If you don’t pass an argument it will only remove and return the very first element: + +` numbers = [2, 4, 6]` +` numbers.shift` *# => 2* +` numbers` *# => [4, 6]* + +Similar to `pop`, `shift` will return *nil* if it is called on an empty Array: + +` [].shift` *# => nil* + +## Removing elements after a specific index + +There might be situations where you want to select all elements of an Array after +a certain position, e.g. all elements after the third element. +You can do this with the `drop` method: + +` fruits = ['apple', 'pear', 'lemon', 'melon']` +` fruits.drop(2)` *# => ["lemon", "melon"]* +` fruits` *# => ["apple", "pear", "lemon", "melon"]* + +In contrast to `pop` and `shift`, `drop` does not modify the original Array but +creates a new Array that comprises the dropped elements. + +## Removing specific elements + +In case you know the elements in an Array, you can specificly remove these. +There are two similar methods for doing this: `delete` and `-`. + +The difference is, that `delete` modifies the original Array, while `-` creates a new +Array and does not change the original Array. + +`delete` takes the element that should be removed from the Array and returns the +removed element: + +` fruits = ['apple', 'lemon', 'lemon']` + +` fruits.delete('lemon')` *# => "lemon"* +` fruits` *# => ["apple"]* + +As you can see, `delete` removes duplicated elements from the Array, here all the +*'lemon'* elements. + +The `-` method takes an Array as argument. It also removes duplicated elements: + +` fruits = ['apple', 'lemon', 'lemon', 'melon']` + +` less_fruits = fruits - ['lemon']` *# => ["apple", "melon"]* +` fruits` *# => ["apple", "lemon", "lemon", "melon"]* + +The `-` does not modify the original Array but creates a new one. The original +Array that is stored in *fruits* remains the same. + +Before going to this unit‘s task, let’s summarize all the learned methods for removing +elements from an Array: + +` pop` *removes elements at end modifies the original Array* +` shift` *removes elements at beginning modifies the original Array* +` drop` *remove elements after given index creates a new Array* +` delete` *removes the given element modifies the original Array* +` -` *removes the given elements creates a new Array* + +--- + +Let’s use our baggage again and unpack a couple of things. +Define a variable *baggage* and assign an array with all the things you want to +take with you: *shoes*, *underwear*, *socks*, *kettle*, *glasses*, *shirt*, and *wallet*. + +You just realized, that you actually want to wear your *shoes* (which are the first +thing in your baggage), so remove them from your *baggage*. + +Your friend tells you that you won’t need the *kettle*, so delete it from your *baggage*, too. + +Last, you think that it’s maybe a better idea to carry your *wallet* with you. +Thus, also pop the wallet from your *baggage*. + +Now you’re good to go. Bon voyage! + +---