Software Engineering Foundations - Week 2 Flashcards

1
Q

What is the DRY rule?

A

Don’t Repeat Yourself and avoid repeating code

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
2
Q

How do you create a class? What is the benefit of creating a class?

A

Class allows you to apply the DRY rule to avoid having to repeat bits of information over and over again.

To create a class we use the < “class” > keyword, and the name of a class must begin with a capital letter.

for example…

class Cat
  def initialize(name, color, age)
    @name = name
    @color = color
    @age = age
  end
end

The @ symbol denotes an instance variable or attribute of our class

So for the example above, the Cat class will have attributes of @name, @color, @age

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
3
Q

After initializing a class, how do we execute upon it and create instances or objects associated with the class?

A

Once you’ve initialized your class, you can create a new object under that class by using < class name >.new( attributes ).

The class name should be the singular of whatever object is being defined like “Cat” instead of “Cats.”

class Cat
  def initialize(name, color, age)
    @name = name
    @color = color
    @age = age
  end
end
cat_1 = Cat.new("Sennacy", "brown", 3)
cat_2 = Cat.new("Whiskers", "white", 5)
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
4
Q

What is a Getter Method?

A

Way to get or return an attribute of an object belonging to a class. So in this example for Cat, we created the “get_name” method which calls on the “@name” attribute.

To execute on the getter method, we need to call on the cat INSTANCE (i.e. cat_1) instead of the class. It’s called, using this format “ < instance name >. “ -> cat_1.get_name

Without the getter method, there’s no way to refer or grab that attribute. A getter method can only return the value of an attribute. It cannot be used to modify the attribute like changing the cat’s age.

class Cat
  def initialize(name, color, age)
    @name = name
    @color = color
    @age = age
  end

def name
@name
end
end

def color
@color
end
end

cat_1 = Cat.new(“Sennacy”, “brown”, 3)
p cat_1.name # “Sennacy”
p cat_1.color #”brown”

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
5
Q

What is a Setter Method?

A

IMPORTANT: You need to set the Getter method FIRST before you can create the Setter Method. The Setter Method will not work without the Getter method created first.

Allows you to change the value of an attribute after it’s already been “set”.

For the cat_1 example below, the age was originally 3, but say we want to change to 42. We can do that by creating a “setter” method where we add “age = number”

class Cat
  def initialize(name, color, age)
    @name = name
    @color = color
    @age = age
  end

def age = (number)
@age = number
end
end

cat_1 = Cat.new("Sennacy", "brown", 3)
cat_1.age = 42 #this will change the value of the age from 3 to 42
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
6
Q

What are ways to implement other types of methods within a class?

A
class Cat
  def initialize(name, color, age)
    @name = name
    @color = color
    @age = age
  end
  def purr
    if @age > 5
      puts @name.upcase + " goes purrrrrr..."
    else
      puts "..."
    end
  end
end

cat_1 = Cat.new(“Sennacy”, “brown”, 10)
cat_1.purr # “SENNACY goes purrrrrr…”

cat_2 = Cat.new(“Whiskers”, “white”, 3)
cat_2.purr # “…”

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
7
Q

What is a Class Variable?

A

An instance variable are denoted by @ and typically assigned insider the #initialize when creating a class. The instance variable is shared attribute across all objects of that class but the attribute itself can change from object to object. Like cars having different colors.

The CLASS VARIABLE sits outside of the #initialize (but still within the Class definition) and is denoted by @@. The @@ClassVariable is a single shared variable across all objects. E.g. the class variable -> @@num_wheels will be 4 and all cars under the Car class will have 4 wheels.

Class variables can be changed but once it changes, it’ll affect every instance created once it changes and will create in the future.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
8
Q

What is a Class Constant?

A

For safety, you can create a class constant which cannot be reassigned. A class constant name must be capitalized.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
9
Q

What are the three different ways to create a variable within a class?

A
  1. an @instance_variable will be a distinct variable in each instance of a class; changing the variable will only affect that one instance
    e. g. @color, if you change the color for dog_1 but not dog_2, then it’ll only affect dog_1.
  2. a @@class_variable will be shared among all instances of a class; changing the variable will effect all instances because all instances of the class
    e. g. @@num_wheels will remain 4 for all cars in the class. But once you change to zero, it’ll affect all future objects of the class.
  3. a CLASS_CONSTANT will be shared among all instances of a class, but cannot be changed
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
10
Q

What is an Instance Method?

A

An instance method is a method that calls on an instance of a class.

In the example below, “#speak” is an instance method as it calls on the Dog instance we initialized using Dog.new.

If something is an instance of a class, it shares the same instance attributes (@) and can be created with < class name >.new

class Dog
  def initialize(name, bark)
    @name = name
    @bark = bark
  end

def speak
@name + “ says “ + @bark
end
end

my_dog = Dog.new(“Fido”, “woof”)
my_dog.speak # “Fido says woof”

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
11
Q

What is a Class Method? What is the symbol associated with it?

A

A Class Method is a method that calls directly on the class by adding “self.” before the method name. Here’s the example “self.growl”. A Class method applies to all objects within the class.

ASSOCIATED WITH DOUBLE COLONS “::”

For notation we’ll use Dog::growl to denote that growl is a class method of Dog.

We then call on the method by using . = i.e. Dog.growl

Class#method_name means method_name is an instance method (e.g. my_dog.speak -> will only work with my_dog the object)

Class::method_name means method_name is a class method (e.g. Dog.growl -> applies to the whole class)

class Dog
  def initialize(name, bark)
    @name = name
    @bark = bark
  end
  def self.whos_louder(dog_1, dog_2)
    if dog_1.bark.length > dog_2.bark.length
      return dog_1.name
    elsif dog_1.bark.length < dog_2.bark.length
      return dog_2.name
    else
      return nil
    end
  end

def name
@name
end

def bark
@bark
end
end

d1 = Dog.new(“Fido”, “woof”)
d2 = Dog.new(“Doge”, “much bork”)
p Dog.whos_louder(d1, d2) # “Doge”

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
12
Q

How do you “monkey patch” or add methods within a class like class Array?

A

Create the method like normal but use “self” to refer to the Array or whatever class is being used.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
13
Q

What is Separation of Concerns?

A

A design principle that focuses on implement one class in a single file for greater organization and clarity.

See example below. Anything without the .rb ending is a folder like “project root” and
“other_animals”

project_root
  ├── pet_hotel.rb
  ├── cat.rb
  └── other_animals
      └── dog.rb
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
14
Q

What is Require Relative?

A

“require_relative” is a method used to specify a path to another ruby file.

For example…see below. To run our hotel, we would just need to execute ruby pet_hotel.rb. Because pet_hotel.rb AS THE MASTER FILE requires cat.rb and dog.rb, the code in those files will also execute.

project_root/pet_hotel.rb

# Let's require the last two files, by specifying their path's relative to this pet_hotel.rb file
require_relative "./cat.rb"
require_relative "./other_animals/dog.rb"
class PetHotel
  def initialize(name)
    @name = name
    @guests = []
  end
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
15
Q

What is the difference between running just “require” and “require_relative”?

A

We use the plain require because we run the code using RSPEC via bundle exec rspec. RSPEC will automatically run the code in a certain configuration where it will automatically know to look inside of the /lib folder. In fact, RSPEC is designed to be used where you have a separate /spec and /lib folders. To get into the nitty gritty details, RSPEC will configure the $LOAD_PATH for us.

As a rule of thumb, we’ll use the plain require where gems are involved. In the previous sections that used the byebug gem, we had to write require “byebug” to access the debugger. It’s obvious that we don’t have an explicit byebug.rb file in those old projects. This is because ruby already knows where to find byebug through the $LOAD_PATH.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
16
Q

What is the built-in method for user input?

A

“gets” - built-in method will halt execution of the code and allows the user to type characters until they hit enter.

p “Enter your name:”
name = gets
p “hello “ + name

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
17
Q

What’s a nuisance of getting user input? How do we deal with it?

A

When user hits the “enter” button, it’ll translate to adding “\n” a newline code to the end of the user-typed response.

Need to add .chomp at the end to remove the newline or carriage return characters.

puts “Enter ‘yes’ or ‘no’”

response = gets.chomp

if response == "yes"
  puts "yup!"
elsif response == "no"
  puts "nah!"
else
  puts "I'm sorry, my responses are limited."
end
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
18
Q

What happens with a user inputs a number? How do we deal with it?

A

A common error is when a user inputs an integer and it automatically comes back as a string.

Need to convert to an integer using “.to_i”

puts “Enter a number: “
num = gets.chomp.to_i
puts 2 * num

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
19
Q

What are the two pillars of Object Oriented Programming (OOP)?

A
  1. Abstraction = abstraction is the process of exposing essential features of an object while hiding inner details that are not necessary to using the feature. Take this analogy: Many drivers do not understand the mechanical details of how a steering wheel works, but they can still use the steering wheel to drive a car. In a similar way, our classes should have methods that are simple to use because they hide complex logic inside of them.

Another example, Array is a class and Array#include? is a method that we feel comfortable using although we do not know the exact implementation details within the method

  1. Encapsulation = is like a protective shield that prevents the data from being accessed by the code outside the shield.

Encapsulation can be achieved by declaring all the variables in the class as private and writing public methods in the class to set and get the values of variables.

For example, if there was a Queue class and within the class methods to define adding and removing people from the line. To avoid havoc, the queue class will avoid any getter or setter methods to be able to enforce the rules and keep it secure.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
20
Q

What is a method to create getters automatically to avoid repetition?

A

“attr_reader” is a built-in method that is called inside a Class (but not within “initialize”).

They’re passed in as symbols that correspond to the attributes that need getters.

By convention, we omit parentheses for attr methods but they can take multiple attributes at a time.

Examples:

attr_reader(:name, :age) is the same as attr_reader :name, :age

class MyClass
attr_reader :attribute_1
# …
end

21
Q

What is a built in method to automatically create setter methods?

A

“attr_writer”

attr_writer :name, :age is the equivalent of explicitly writing out a setter method like below:

def name=(new_name)
@name = (new_name)
end

def age=(new_age)
@age = (new_age)
end

22
Q

What is a built in method that allows you to create both a getter and setter method?

A

“attr_accessor” simultaneously gets and sets the attributes. Should be used sparingly given that data may need to be encapsulated or shielded from misuse.

attr_accessor :name, :age

23
Q

What is Syntactic Sugar?

A

these are “shortcuts” to make the code more readable and elegant.

def ==(other_person)
self.last_name == other_person.last_name
end

For example, instead of this
person_1.==(person_2)

do this instead…
person_1 == person_2

24
Q

How can you create a random number?

A

rand(min..max)

25
Q

When initializing an instance what do you do?

A

Class name.new (parameters as defined in initialize)

for e.g.
Hotel.new(capacity)

26
Q

If there are two criteria to fulfill, what can you do?

A

Nested if else statements - like Russian doll

27
Q

What do you need to include if you need the value to be returned on NEW lines?

A

“puts”

28
Q

What is the difference between defining and calling on a class method?

A

When defining a class method use self, when calling it else where, use the class name

29
Q

When given a length and an array of valid characters, how can I create a randomized version?

A

valid_chars = [“a”, “b”, “c”, “d”]
randomized = [ ]
length.times { randomized &laquo_space;valid.chars.sample }

30
Q

What does the .sample built in method do?

A

Works on only arrays. Will return an element from the array at random. You can also provide how many samples.

.sample(4) = outputs 4 random elements

31
Q

In tic tac toe, how would you swap the current_player?

A

use the swapping parallel assignment, same as bubble sort

x, y = y, x

32
Q

Create a method that transposes a 2D array of square size without using the built in method?

A

def my_transpose
transposed = Array.new(self[0].length) { Array.new(self.length) }
(0…self.length).each do |i1|
(0…self[0].length).each do |i2|
transposed[i2][i1] = self[i1][i2]
end
end
transposed
end

33
Q

What is one thing to remember about true or false responses when there are multiple lines nested within the if statement? < e.g. Hangman#try_guess >

A

Make sure the true or false return is the very last line of code. Don’t alway nest if you don’t have to.

34
Q

When working with different and connected classes, what do you need to pay attention to?

A

When another class is being initialized in another class or if i have to initialize myself. like Room.new within the Hotel class.

35
Q

What’s a rule of thumb when using @ vs. self?

A

If just a getter method or attr_reader, use @. If self is being used, must have a setter method too (or accessor)

36
Q

General things to remember…

  1. hash.has_key?
  2. adding two arrays together
A
  1. Make sure you dont have a syntax error with hash.has_key?(). Use parenthesis instead of brackets
  2. when adding two arrays together can just do array 1 + array 2 but check to see if array 1 needs to be reassigned as the sum of the two arrays
37
Q

Bracket methods like #[ ] or #[ ]=…what is one thing to remember when calling on it?

A

IT’S A METHOD so needs self added before it

like self[position] or self[position] =

38
Q

How can you find the count of EXACT string matches like for bigrams?

A

str.scan(/(exact str)/) = will spit out an array, then take the length of the array to get the count

39
Q

How do you create a recursive method to find the factorial of n?

A
  1. Establish a base case which is that if n = 1 then it’ll return 1
  2. create an anchor to then be able to call the method on itself

def factorial(n)
return 1 if n == 1
n * factorial(n-1)
end

40
Q

How do you create a recursive method to find the nth number of the fibonacci sequence?

A
  1. The first two numbers are 1 in the fibonnaci sequence so that they’re our base cases as the next number will take the sum of the last two.

def fib(n)
return 1 if n == 1 || n == 2
fib(n-1) + fib (n-2)
end

41
Q

What does the spaceship operator <=> do?

A
  1. Returns 1 if the element on the left is greater than the one on the right
  2. Returns -1 if the element on the left is lower than the one on the right
  3. Returns 0 if the two elements match each other.
42
Q

Write a method, pow(base, exponent), that takes in two numbers. The method should calculate the base raised to the exponent power.

A
def pow(base, exponent)
    return 1 if exponent == 0
    return base if exponent == 1
base * pow(base, exponent-1)

end

43
Q

Write a method that takes in an array and recursively finds the sum of all the elements in the array.

A
def sum_array(array)
    return 0 if array == []
    return array.first if array.length == 1
sum_array(array[0...1]) + sum_array(array[1..-1])

end

44
Q

Write a method that takes in a string and return the string with its characters in reverse order.

A
def reverse_string(str)
    return "" if str == ""
    return str if str.length == 1
str[-1] + reverse_string(str[0...-1])

end

45
Q

What is the difference between shoveling and concating or using (+=) two separate arrays?

A

Shoveling will retain the dimensions while concating or adding together arrays will FLATTEN them.

46
Q

A 1-dimensional array is also known as a flattened array. Write a method, flatten(data), that accepts a single argument. The method should take in an array of any dimension and return the flattened version of that array. Solve this recursively.

A

MUST CONCATENATE THE ARRAYS WHEN ADDING WITH RECURSIVE METHOD

def flatten(data)

return [data] if !(data.is_a?(Array))

flattened = []
    data.each do |element|
        if !element.is_a?(Array)
            flattened << element
        else
            flattened += flatten(element)
        end
    end
flattened

end

47
Q

lucas_sequence
The Lucas Sequence is a sequence of numbers. The first number of the sequence is 2. The second number of the Lucas Sequence is 1. To generate the next number of the sequence, we add up the previous two numbers. For example, the first six numbers of the sequence are: 2, 1, 3, 4, 7, 11, …

Write a method lucasSequence that accepts a number representing a length as an arg. The method should return an array containing the Lucas Sequence up to the given length. Solve this recursively.

A

def lucas_sequence(n)

return [] if n == 0
return [2] if n == 1
return [2, 1] if n == 2

sequence = lucas_sequence(n - 1)
sequence << sequence[-1] + sequence[-2]
sequence end
48
Q

prime_factorization
The Fundamental Theorem of Arithmetic states that every positive integer is either a prime or can be represented as a product of prime numbers.

Write a method prime_factorization(num) that accepts a number and returns an array representing the prime factorization of the given number. This means that the array should contain only prime numbers that multiply together to the given num. The array returned should contain numbers in ascending order. Do this recursively.

A

STARTS WITH TWO AS THE LOWEST PRIME, KEEPS GOING UNTIL IT FINDS THE NEXT NUMBER DIVISIBLE AND THEN BREAKS IT DOWN AGAIN.

  1. For example, prime factorization of 25. Starts at 2…nothing divisible until it reaches 5, then takes 25 / 5 and starts again with 5. Enumerates from 2 to 5 but there is nothing divisible so it STOPS THE ITERATION. And telling it to then return the result of the two factorizations.
  2. For prime factorization of 24, Starts at 2. 2 is divisible by 24 but can’t broken out into smaller primes so its stored. Then it divides 24 by 2 = 12 and iterates from 2..12. Again, it stops at 2 since its divisible by 12 and the new_factor is then 6 and [2,2] are now stored. Starts over and iterates from 2..6 and again 2 is divisible, and stored so now its [2,2,2] and 6/2 = 3 which is new factor and iterates from 2..3. Since 3 is already a prime number it returns it. so final result will be [2,2,2,3]
def prime_factorization(n)
    result = []
    if is_prime?(n)
        return [n]
    end
(2...n).each do |factor|
    if is_prime?(factor) && (n % factor == 0)
        new_factor = n / factor
        return [prime_factorization(factor),prime_factorization(new_factor)].flatten
    end
end

end

def is_prime?(num)
    return false if num < 2
    (2...num).each { |div| return false if num % div == 0 }
    return true
end
# Examples
p prime_factorization(12)     # => [2, 2, 3]
p prime_factorization(24)     # => [2, 2, 2, 3]
p prime_factorization(25)     # => [5, 5]
p prime_factorization(60)     # => [2, 2, 3, 5]
p prime_factorization(7)      # => [7]
p prime_factorization(11)     # => [11]
p prime_factorization(2017)   # => [2017]
49
Q

prime_factorization
The Fundamental Theorem of Arithmetic states that every positive integer is either a prime or can be represented as a product of prime numbers.

Write a method prime_factorization(num) that accepts a number and returns an array representing the prime factorization of the given number. This means that the array should contain only prime numbers that multiply together to the given num. The array returned should contain numbers in ascending order. Do this recursively.

A
def prime_factorization(n)
    result = []
    if is_prime?(n)
        return [n]
    end
(2...n).each do |factor|
    if is_prime?(factor) && (n % factor == 0)
        new_factor = n / factor
        return [prime_factorization(factor),prime_factorization(new_factor)].flatten
    end
end

end

def is_prime?(num)
    return false if num < 2
    (2...num).each { |div| return false if num % div == 0 }
    return true
end
# Examples
p prime_factorization(12)     # => [2, 2, 3]
p prime_factorization(24)     # => [2, 2, 2, 3]
p prime_factorization(25)     # => [5, 5]
p prime_factorization(60)     # => [2, 2, 3, 5]
p prime_factorization(7)      # => [7]
p prime_factorization(11)     # => [11]
p prime_factorization(2017)   # => [2017]