Software Engineering Foundations - Week 1 Flashcards
How can I check if all the numbers in this array are even numbers?
arr = [2, 4, 6, 8]
arr.all?(&:even?)
How can I check if the numbers in this array are NOT even numbers?
arr = [2, 4, 6, 8]
arr.none?(&:even?)
How can I check if any of the numbers in this array are odd numbers?
arr = [2, 4, 7, 8, 9]
arr.any?(&:odd?)
How can I check if just a single number in this array is an odd number?
arr = [2, 4, 7, 8]
arr.one?(&:odd?)
How can I split an array based on all the values that evaluate to true and all the values that evaluate to false?
Separate out the even vs. odd numbers
arr = [2, 4, 7, 8, 9]
arr. partition(&:even?)
output: [2,4,8] [7,9]
How can I check if the array does not contain any duplicate elements?
arr = [2, 4, 7, 8, 9, 7, 2]
arr.uniq.length == arr.length
Reducing the array to just the uniques and seeing if the length of the reduced array and original array are the same
How can I return a new array to just the even numbers?
arr = [2, 4, 7, 8, 9, 7, 2]
arr.select(&:even?)
or can be written
arr.select { |num| num.even? }
How can I merge two arrays together to have corresponding elements of the same indices together?
array_a = [ 4, 5, 6 ] array_b = [ 7, 8, 9 ]
array_a.zip(array_b)
output: [[4, 7], [5, 8], [6, 9]]
What happens when you merge two arrays together at corresponding indices but the two arrays have different lengths?
array_a = [ 4, 5, 6 ] array_b = [ 7 ] array_c = [ 1, 2]
Need to zip with the largest array first with the other smaller arrays listed as the parameters to make sure all values are captured. Any empty values will appear as “nil”
array_a = [ 4, 5, 6 ] array_b = [ 7 ] array_c = [ 1, 2]
array_a.zip(array_b, array_c)
output : [[4, 7, 1], [5, nil, 2], [6, nil, nil]]
Return a new array with the start number and length provided and multiply each number by 2
p test(2, 4)
def test(start, length) arr = [start] (0...length-1).map { |i| arr << arr[-1] * 2 } arr end
output: [2, 4, 8, 16]
What type of enumerable allows you to iterate through an array and accrue information over the duration of the iteration?
What are the different ways this enumerable can be used?
What is it synonymous with?
.inject is interchangeable with .reduce
If you do not explicitly specify an initial value for memo, then the first element of collection is used as the initial value of memo.
Ways to use it:
- array.inject(:+) - to sum all the numbers in an array. Can also be written like…
arr. inject { |memo, e| memo + e} where memo is the accumulator - array.inject { | memo, e | memo > e ? memo : e } - returns the highest number in the array
- array.inject([]) { | memo, ele | memo «_space;ele * 3 if ele.is_a?(Integer) }
array = [1, 5, “dog”, :yes, 6, 1000, “three-hundred”]
in this example, i’m using an empty array as my initial value and then shoveling into the array only the integers multiplied by 3
- def test(a, b)
a.inject({}) do |memo, name| memo[name] = b[a.index(name)]
memo
end
a = ["Sally", "Beatrice", "Bob", "Molly"] b = ["421-4921", "293-1839", "104-1273", "483-2894"]
output :
{“Sally”=>”421-4921”, “Beatrice”=>”293-1839”, “Bob”=>”104-1273”, “Molly”=>”483-2894”}
Iterate through this array and return a new array with the element and their corresponding indices in individual sub-arrays
arr = [2, 4, 7, 8, 9, 7, 2]
def test(arr) result = [] arr.each_with_index { |e, i| result << [e,i] } result end
output: [[2, 0], [4, 1], [7, 2], [8, 3], [9, 4], [7, 5], [2, 6]]
Write a method combinations that takes in an array of unique elements, the method should return a 2D array representing all possible combinations of 2 elements of the array.
arr = ([“a”, “b”, “c”])
To create a 2D array from a single array requires iterating through the same array twice and to find unique combinations with no duplicates, need to make sure the index of the inner array is greater than the indices in outer array
def test(arr)
pairs = []
arr.each_with_index do |ele_1, idx_1|
arr.each_with_index do |ele_2, idx_2|
pairs «_space;[ele_1, ele_2] if idx_2 > idx_1
end
end
pairs
end
What is a symbol?
Symbols are designated by “ : “ and cannot be immutable,. and will have the same object ID throughout the code. While it cannot be reassigned, the characteristics of the symbol can be changed.
str = "hello" sym = :hello
str[0] = "x" sym[0] = "x"
p str # => “xello”
p sym # => :hello
Symbols can also be used as hash keys { :name = “Ann” }
hash[:name]
What is a splat? What are the 3 ways of using it?
- A splat lets you use additional arguments so you don’t get an “ArgumentError” with the wrong number of arguments.
- A splat can also be used to decompose an array
arr_1 = [“a”, “b”]
arr_2 = [“d”, “e”]
arr_3 = [ *arr_1, “c”, *arr_2 ]
p arr_3 # => [“a”, “b”, “c”, “d”, “e”]
- A double splat (**) can also be used to decompose a hash . Double splat will only work with hashes where the keys are symbols.
old_hash = { a: 1, b: 2 }
new_hash = { **old_hash, c: 3 }
p new_hash # => {:a=>1, :b=>2, :c=>3}
What are the two ways to create a GLOBAL scope that can accessed outside of a method?
- Using $ like $message
2. Using CAPITAL letters to create a “Constant” variable. a Constant variable like a symbol cannot be reassigned.
What is lexical scope?
Lexical scope describes how a variable name evaluates in nested code. All methods have local scopes.
What is an algorithm?
Sequence of actions to complete a task - sorting algorithms
How do you implement a bubble sort algorithm?
arr = [2, 9, 4, 5, 6, 1]
def bubble_sort(arr) sorted = true while sorted sorted = false (0...arr.length-1).each do |i| if arr[i] > arr[i+1] arr[i], arr[i+1] = arr[i+1], arr[i] sorted = true end end end arr end
output: [1, 2, 4, 5, 6, 9]
What is one way to handle a native exception like ZeroDivisionError?
Ways to raise an error
“Begin…rescue” (Under “begin” you insert the code that would occur when it can be successfully run. Under “rescue” you put the desired output for when there’s an error”
begin puts "dividing 10 by #{num}" ans = 10 / num puts "the answer is #{ans}" rescue puts "There was an error with that division." end
Write a method, my_rotate!(array, amt), that accepts an array and a number as args.
The method should mutate the array by rotating the elements ‘amt’ number of times.
When given a positive ‘amt’, a single rotation will rotate left, causing the first element to move to the last index
When given a negative ‘amt’, a single rotation will rotate right, causing the last element to move to the first index
The method should return the given array. Do not use the built-in Array#rotate
def my_rotate!(array, amt) if amt > 0 amt.times { first = array.shift array.push(first) } elsif amt < 0 amt.abs.times { last = array.pop array.unshift(last) } end array end
array_1 = [“a”, “b”, “c”, “d”]
result_1 = my_rotate!(array_1, 2)
p result_1 # => [“c”, “d”, “a”, “b”]
array_2 = [“NOMAD”, “SOHO”, “TRIBECA”]
result_2 = my_rotate!(array_2, 1)
p result_2 # => [“SOHO”, “TRIBECA”, “NOMAD”]
array_3 = [“a”, “b”, “c”, “d”]
result_3 = my_rotate!(array_3, -3)
p result_3 # => [“b”, “c”, “d”, “a”]
Write a method that return true or false if an array is sorted or not.
def is_sorted(arr) (0...arr.length-1).each do |i| if arr[i] > arr[i+1] return false end end return true end
p is_sorted([1, 4, 10, 13, 15]) # => true p is_sorted([1, 4, 10, 10, 13, 15]) # => true p is_sorted([1, 2, 5, 3, 4 ]) # => false
How do you implement a bubble sort alogrithm with the below array?
arr = [2, 9, 4, 5, 6, 1]
def bubble_sort(arr)
Write a method, compress_str(str), that accepts a string as an arg. The method should return a new str where streaks of consecutive characters are compressed. For example “aaabbc” is compressed to “3a2bc”.
def compress_str(str) compressed = "" i = 0 while i < str.length char = str[i] count = 0 while char == str[i] count += 1 i += 1 end count == 1 ? (compressed += char) : (compressed += count.to_s + char) end compressed end
p compress_str("aaabbc") # => "3a2bc" p compress_str("xxyyyyzz") # => "2x4y2z" p compress_str("qqqqq") # => "5q" p compress_str("mississippi") # => "mi2si2si2pi"
What is TDD?
Test Driven Development is a strategy to develop programs where requirements for the program are turned to test cases. Need to make sure the method is AIR TIGHT and not subject to false positives or false negatives.
- Write a new test
- Run all the test and check for fail - first first test should always fail (check for nil for example)
- Make changes to the method to satisfy all the tests
- Run all tests and check for passes. If any of the tests fail, go back to step 3. If all the tests pass but more coverage is needed, go back to step 1.
How can we implement our own exceptions?
By default, the program will terminate when an exception occurs so there are ways to handle an exception so the program doesn’t shut off.
Raising an exception means stopping normal execution of the program and transferring the flow-of-control to the exception handling code where you either deal with the problem that’s been encountered or exit the program completely.
def format_name(first, last)
if !(first.instance_of?(String) && last.instance_of?(String))
raise “arguments must be strings”
end
first.capitalize + “ “ + last.capitalize
end
format_name(“grace”, “hopper”) # => “Grace Hopper”
format_name(42, true) # => RuntimeError: arguments must be strings
What is a Proc? How do you use it?
A proc is a wrapper for a block code and can be made into a object.
Initialize the proc by using Proc.new { block code }
Accept a block as an argument, change to Proc by using “&” to convert
Accept a proc as argument, no need to convert or use the “&”
Proc can be called using the “.call(param)” method
What is a block?
Block is a chunk of code that is passed through a method to be executed. There are two ways to execute a block
- { } if just using one line of code
- do…end if using multi-lines of code
A block can accept a parameter if we’re naming them in between the | |
What is a Proc?
A proc is a wrapper for a block code and can be made into a object.
Initialize the proc by using Proc.new { block code }
Accept a block as an argument, change to Proc by using “&” to convert
Accept a proc as argument, no need to convert or use the “&”
Write a method that accepts any value and an array of procs as an argument. The method should return the final result of feeding the value through all of the procs. For example, if the array contains three procs, then:
- the value is given to the first proc
- the result of the first proc is given to the second proc
the result of the second proc is given to the third proc - the result of third proc is the final result
This needs a simple inject method.
def chain_map(v, arr) arr.inject(v) do |memo, prc| prc.call(memo) end end
add_5 = Proc.new { |n| n + 5 } half = Proc.new { |n| n / 2.0 } square = Proc.new { |n| n * n }
p chain_map(25, [add_5, half]) # 15.0 p chain_map(25, [half, add_5]) # 17.5 p chain_map(25, [add_5, half, square]) # 225 p chain_map(4, [square, half]) # 8 p chain_map(4, [half, square]) # 4
Write a method that accepts a word as an arg and returns the word with its last vowel removed - e.g. “tonic” -> “tonc”
Change to an array of characters and iterate backwards with a while loop. When it hits its first vowel, break the loop.
def hipsterfy(word) chars = word.chars i = chars.length-1 while i >= 0 if 'AEIOUaeiou'.include?(chars[i]) chars[i] = "" break end i -= 1 end chars.join end
Write a method that accepts a message and returns a new string where every letter of the message is shifted “n” positions in the alphabet. It should not modify any non-alphabetic characters.
def caesar_cipher(message, n) alphabet = "a".upto("z").to_a message.downcase.chars.map { |char| !alphabet.include?(char) ? char : alphabet[(alphabet.index(char) + n) % 26] }.join end
Write a method vowel_counts where it should accept string as an arg and should return a hash where each key is a vowel of string and it’s value is the number of times it appears.
input : “williamsburg bridge”
output: {“i”=>3, “a”=>1, “u”=>1, “e”=>1})
input : “WILLIAMSBURG bridge”
output: {“i”=>3, “a”=>1, “u”=>1, “e”=>1})
def vowel_counts(str) hash = {} str.downcase.chars.each do |char| if 'AEIOUaeiou'.include?(char) hash[char] = str.downcase.chars.count(char) end end hash end
How do you use Byebug to debug?
- First make sure the command < require “byebug” > is in the implementation file
- Add < debugger > in the line of code you want to pause
- run your rspec with < bundle exec rspec >
- If byebug isn’t working, use < gem install byebug >
- “c” = continue through the method
- “n” = next
- ”s” = step into a method, need to make sure you’re in a line of code that can be stepped into
What are things to look for in debugging?
- Are any variables sitting outside of the method and can’t be accessed?
- If comparing two variables, is it using two equal signs == ?
- Are splits, splitting correctly?
- Are true and falses properly structured?
- Are any methods looking at case sensitive characters?
Write a method dupe_indices that accepts an array as an arg and return a hash where keys are the elements that were repeated in the array and the values are the indices where the elements appeared.
input : [“a”, “b”, “c”, “c”, “b”]
output : {“b”=>[1,4], “c”=>[2,3]}
def dupe_indices(arr) hash = arr.each_with_index.group_by(&:first).select { |k,v| v.length >= 2 } hash.each { |k,v| v.map!(&:last)} end
Create a hash using the k/v pairs with the key being the element and the v being the element and index.
Then want to modify the hash to only keep the repeated characters which means they will have a value length of greater than 2 or more
Then need to re-map the values to only include the indices (i.e. “last”)
Write a method that accepts two arrays as args. When the arrays contain the same elements in any order it should return true.
input : [“cat”, “dog”, “cat”], [“dog”, “cat”, “cat”]
output : true
input : [“cat”, “dog”, “cat”], [“dog”, “cat”, “mouse”]
output : false
def ana_array(arr_1, arr_2) merged = [arr_1, arr_2].flatten.uniq merged.each { |e| return false if !(arr_1.include?(e) && arr_2.include?(e)) } return true end
Merge the two arrays together, flatten into one and then collect only the unique elements.
Look to see if there are any elements that are NOT in both arrays.
Only when it’s checked all the arrays, return true
Write a method that accepts a 2d array and returns the count of sub-arrays the sum to a positive number, using the .count method
input : array_1 = [ [-2, 5], [1, -9, 1], [4, 7] ]
output : 2
def count_positive_subarrays(arr) arr.count { |sub| sub.sum > 0 } end
Write a method aba_translate that takes a word string and transforms the word by putting a “b” after every vowel and adding that same vowel.
input : “cats”
output : “cabats”
input : “dog”
ouput : “dobog”
def aba_translate(word) word.chars.map { |char| 'AEIOUaeiou'.include?(char) ? char + "b" + char : char }.join("") end
Write a method that accepts an array of words and returns true or false if words are properly capitalized.
input : [“hello”, “world”]
output : false
input : [“Hello”, “World”]
output : true
def all_words_capitalized?(arr) arr.all? { |word| word == word.capitalize } end
Write a method that checks if all of the URLs end with a proper URL ending
valid = [‘.com’, ‘.net’, ‘.io’, ‘.org’]
input : [“appacademy.io”, “sennacy.com”, “heyprogrammers.org”]
output: true
USE THE SPLAT TO DECOMPOSE THE ARRAY OF VALID ENDINGS
arr.all? { | url | url.end_with?(*valid) }
Write a method that takes an array of students hashes and use .any? to see if ANY of the students have an average grade of 75 or higher.
input : students_1 = [ { name: "Alvin", grades: [70, 50, 75] }, { name: "Warlin", grades: [80, 99, 95] }, { name: "Vlad", grades: [100] }, ]
output : true
def any_passing_students?(arr) arr.any? { |grade| (grade[:grades].sum / grade[:grades].length) >= 75 } end
What is the built in method to rotate an array and what is required to rotate it in the opposite direction
arr.rotate(x) where x is the number of times it needs to rotate
If x is a positive number, the first element becomes the last element
If x is a negative number, the last element becomes the first
What is the difference between zip and transpose? What is the purpose of each?
Transpose only works with 2d arrays
input :
arr = [[2,5,1], [3,4,7]]
arr.transpose
output : [2,3] [5,4] [1,7]
Zip will work with individual arrays as separate and individual objects.
Zip and transpose will do the same thing where it combines two arrays and returns a new 2d array with each element at corresponding indices are grouped together.
input :
arr_1 = [2,5,1]
arr_2 = [3,4,7]
arr_1.zip(arr_2)
output : [2,3] [5,4] [1,7]
How does the group_by function work?
group_by automatically creates a hash where the key is defined or created based on whatever parameters are put in the parenthesis
.group_by(key param)
How do you merge two hashes together? If there are two duplicate keys, take the value of the second value?
What’s another way of doing it?
Using ** double splats to decompose the hash, will take the value of the second hash if there are duplicates
def merge(hash_1, hash_2) result = {**hash_1, **hash_2} end
Another way of doing it is creating a blank hash and then iterating through both hashes. When iterating through the second hash it’ll override any keys that are already existing with the value from the second hash.
def merge(hash_1, hash_2) result = { } hash_1.each { | k, v | result[k] = v } hash_2.each { | k, v | result[k] = v } result end
Create a method when provided a sentence and an array of curse words, censor the curse word by replacing every vowel with an “*”.
input : “Gosh darn it”, [“gosh”, “darn”, “shoot”]
output : “Gsh drn it”
WATCH OUT CASE SENSITIVE and create a helper method
def censor(sentence, arr) sentence.split(" ").map { |word| arr.include?(word.downcase) ? replace_vowel(word) : word }.join(" ") end
def replace_vowel(word) word.chars.map { |char| 'AEIOUaeiou'.include?(char) ? "*" : char }.join end
IMPORTANT : Create substrings from a string
input : “jump”
output : [“j”, “ju”, “jum”, “jump”, “u”, “um”, “ump”, “m”, “mp”, “p”]
First iteration
0
0 1 2 3
Second Iteration
1
1 2 3
Third iteration
2
2 3
Last iteration
3
3
def sub_strings(str) subs = [] (0...str.length).each do | start_i | (start_i...str.length).each do | end_i | subs << str[start_i..end_i] end end subs end
Create a method called palindrome strings where it accepts a string and returns an array containing all substrings that are palindromes and longer than 1 character.
input : “abracadabra”
output: [“aca”, “ada”]
input : “madam”
output : “madam”, “ada”
input : “taco”
output : [ ]
def palindrome_substrings(str) result = substrings(str).select { |sub_str| sub_str.length > 1 } palindromes = [] (0...result.length).each do |i| palindromes << result[i] if palindrome?(result[i]) end palindromes end
What is anti-prime?
https://youtu.be/2JM2oImb9Qg?t=160
Find how many divisors the “master” number has. Then create a helper method to find all the divisors of all the numbers leading up to the master number. Return false if any of the total length of the divisors is greater than the “master” length of divisors.
def anti_prime?(num)
master = (1..num).select { |div| num % div == 0 }.length
(1..num).each do |div|
return false if divisor(div).length > master
end
return true
end
def divisor(num) (1..num).select { |div| num % div == 0} end
Combine two matrices together
Input :
matrix_1 = [[2, 5], [4, 7]]
matrix_2 = [[9, 1], [3, 0]]
Output : [[11, 6], [7, 7]]
structurally
2 5 + 9 1 => 11 6
4 7 3 0 7 7
NEED THE INNER LOOP TO BE THE FIRST SUBARRAY - m1[0]
def matrix_addition(m1, m2)
result = Array.new(m1.length) { Array.new(m1[0].length) {0} }
m1.each_with_index do |e1, i1|
m1[0].each_with_index do |e2, i2|
result[i1][i2] = m1[i1][i2] + m2[i1][i2]
end
end
result
end
Write a method mutual_factors that accepts any amount of numbers as arguments. The method should return an array containing all of the common divisors shared among the arguments.
Input : (50, 30)
Output : [1, 2, 5, 10]
Input : (50, 30, 45, 105)
Output : [1, 5]
Find all the factors and then select only the ones with a count equal to the length of the original input and grab only the unique elements which will grab only the divisors that are common across all the numbers provided.
def mutual_factors(*nums)
factors = []
(0…nums.length).each do |i|
factors «_space;(1..nums[i]).select { |div| nums[i] % div == 0 }
end
factors.flatten.select { |num| factors.flatten.count(num) >= nums.length }.uniq
end
Write a method matrix_addition_reloaded that accepts any number of matrices as arguments. The method should return a new matrix representing the sum of the arguments. Matrix addition can only be performed on matrices of similar dimensions, so if all of the given matrices do not have the same “height” and “width”, then return nil.
def matrix_addition_reloaded(*matrices) matrices.inject do |m1, m2| matrix_addition(m1, m2) if m1.length == m2.length end end
matrix_a = [[2,5], [4,7]] matrix_b = [[9,1], [3,0]] matrix_c = [[-1,0], [0,-1]] matrix_d = [[2, -5], [7, 10], [0, 1]] matrix_e = [[0 , 0], [12, 4], [6, 3]]
p matrix_addition_reloaded(matrix_a, matrix_b) # [[11, 6], [7, 7]] p matrix_addition_reloaded(matrix_a, matrix_b, matrix_c) # [[10, 6], [7, 6]] p matrix_addition_reloaded(matrix_e) # [[0, 0], [12, 4], [6, 3]] p matrix_addition_reloaded(matrix_d, matrix_e) # [[2, -5], [19, 14], [6, 4]] p matrix_addition_reloaded(matrix_a, matrix_b, matrix_e) # nil p matrix_addition_reloaded(matrix_d, matrix_e, matrix_c) # nil
Write a method squarocol? that accepts a 2-dimensional array as an argument. The method should return a boolean indicating whether or not any row or column is completely filled with the same element. You may assume that the 2-dimensional array has “square” dimensions, meaning it’s height is the same as it’s width.
input : [ [:a, :x , :d], [:b, :x , :e], [:c, :x , :f ] output : true
input : [ [:o, :x , :o], [:x, :o , :x], [:o, :x , :o] output : false
Check if all the rows are the same by taking the uniques and seeing if it has just a length of one. Then transpose the array to make the columns into rows and do the same process.
def squarocol?(arr) return true if arr.any? { |sub| sub.uniq.length == 1 } return true if arr.transpose.any? { |sub| sub.uniq.length == 1} return false end
How would you create an adjacent sums method?
input :
arr = [1, 2, 3]
output :
arr = [3, 5]
def adjacent_sums(arr) sums = [ ] (0...arr.length-1).each do |i| sums << arr[i] + arr[i+1] end sums end
Given a number and n, find the nth next prime number of that number
input : 4, 1
output : 5 (first prime # from 4)
input : 4, 2
output : 7 (second prime # from 4)
CREATE A COUNT OF THE PRIMES AND INCREMENT THE NUMBER UNTIL THE COUNT MATCHES THE NTH NUMBER
def next_prime_positive(number, i) prime_count = 0 step = 1 while prime_count < i number += step prime_count += 1 if is_prime?(number) end number end
Return true or false if the same element appears diagonally in both directions
input:
[:x, :y, :o],
[:x, :x, :x],
[:o, :o, :x],
output:
true
Create a helper method to look at the diagonal going left to right, top to bottom and iterate through find the same index pairs ( aka 0,0 - 1,1 - 2,2 ). Shovel the corresponding elements into the array and see if it all matches each other. Then REVERSE the arr to look the opposite diagonal in the same direction from left to right.
def squaragonal?(arr) return true if diagonal(arr) || diagonal(arr.reverse) return false end
def diagonal(arr) diagonal = [ ] arr.each_with_index do |e, i| diagonal << arr[i][i] end diagonal.uniq.length == 1 end
Write a method to check if a number is a power of two.
input : 16
output : true (2 ^ 4)
An example with 16, starts off with 1. 1 is less than 16 so it times it by 2. 2 is less than 16 so times by 2 again. 4 is less than 16. and times by 2 is 8. 8 is less than 16 and times by 2 is 16. 16 is no longer less than 16 and breaks the loops. 16 = 16 so it returns true.
def power(num) product = 1 while product < num product *= 2 end product == num end
Powers of two are = 1, 2, 4, 8, 16, 32, 64…
Find the nth prime number.
MAKE SURE IT’S LESS THAN N, NOT LESS THAN OR EQUAL TO
def nth_prime(n) prime_count = 0 num = 0 while prime_count < n num += 1 prime_count += 1 if is_prime?(num) end num end
Write a method multi_map that accepts an array, an optional number (n), and a block as arguments. The method should return a new array where each element of the original array is repeatedly run through the block n times. If the number argument is not passed in, then the the elements should be run through the block once.
p multi_map(['pretty', 'cool', 'huh?']) { |s| s + '!'} # ["pretty!", "cool!", "huh?!"] p multi_map(['pretty', 'cool', 'huh?'], 1) { |s| s + '!'} # ["pretty!", "cool!", "huh?!"] p multi_map(['pretty', 'cool', 'huh?'], 3) { |s| s + '!'} # ["pretty!!!", "cool!!!", "huh?!!!"]
REASSIGNING THE ARRAY WITHIN A LOOP
def multi_map(arr, n=1, &prc) i = 0 while i < n arr.map! { |e| prc.call(e) } i += 1 end arr end
Write a method that accepts any value and an array of procs as an argument. The method should return the final result of feeding the value through all of the procs. For example, if the array contains three procs, then:
the value is given to the first proc
the result of the first proc is given to the second proc
the result of the second proc is given to the third proc
the result of third proc is the final result
def chain_map(value, procs) procs.inject(value) do |sum, proc| proc.call(sum) end end
add_5 = Proc.new { |n| n + 5 } half = Proc.new { |n| n / 2.0 } square = Proc.new { |n| n * n }
p chain_map(25, [add_5, half]) # 15.0 p chain_map(25, [half, add_5]) # 17.5 p chain_map(25, [add_5, half, square]) # 225 p chain_map(4, [square, half]) # 8 p chain_map(4, [half, square]) # 4
How can you use arr.delete while inside an enumerable
create a carbon copy of the array to iterate through and use .delete on original array so that the iteration doesn’t get messed up
Write a method proc_suffix that accepts a sentence and a hash as arguments. The hash contains procs as keys and suffix strings as values. The method should return a new sentence where each word of the original sentence is appended with a suffix if the original word returns true when given to the corresponding proc key. If an original word returns true for multiple procs, then the suffixes should be appended in the order that they appear in the input hash.
Examples
contains_a = Proc.new { |w| w.include?('a') } three_letters = Proc.new { |w| w.length == 3 } four_letters = Proc.new { |w| w.length == 4 }
p proc_suffix(‘dog cat’,
contains_a => ‘ly’,
three_letters => ‘o’
) # “dogo catlyo”
NEED TO KEEP THE LOOP GOING UNTIL ALL PROCS ARE SATISFIED
def proc_suffix(sentence, hash) result = [] sentence.split(" ").each do |word| temp_word = word hash.each do |k,v| temp_word += v if k.call(word) == true end result << temp_word end result.join(" ") end
Zany Zip (RSPEC Exercise 5). Write a method that accepts any number of arrays of different lengths and zip them together.
WHAT IS THE EASIER WAY OF DOING IT?
Inputs: let(:array_1) { ['a', 'b', 'c'] } let(:array_2) { [1, 2, 3] } let(:array_3) { [11, 13, 15, 17] } let(:array_4) { ['v', 'w', 'x', 'y', 'z'] }
Output: ["a", 1, 11, "v"], ["b", 2, 13, "w"], ["c", 3, 15, "x"], [nil, nil, 17, "y"], [nil, nil, nil, "z"]
EASIER WAY:
1. Since the arrays are of varying lengths need to find the longest length.
- Use map to iterate from 0 to length and then nest another map to iterate through the array and get the corresponding elements at the index.
def zany_zip(*arrays) max_length = arrays.map(&:length).max
(0...max_length).map do |i| arrays.map do |arr| arr[i] end end end
LONG WAY:
- Since the arrays are not the same size, i need to find the length of the largest array.
- I need to iterate through all the sub-arrays which are my “rows” , i.e. the outside index of the index pair [i1][i2].
- Then to iterate through to the maximum number to get all the numbers within each sub-array - the inside index [i1][i2]
- Since i’m “zipping” i need to create a result array with the column = maximum length and rows = # of arrays
- Invert the index pairs and reassign
def zany_zip(*arrs) max_num = arrs.map(&:length).max result = Array.new(max_num) { Array.new(arrs.length) } (0...arrs.length).each do |i1| (0...max_num).each do |i2| result[i2][i1] = arrs[i1][i2] end end result end
Write a method Maximum that accepts an array and a block and return the element that has the largest result when passed into the block. When there’s a tie, it should return the element that appears later in the array.
Input:
[‘boot’, ‘cat’, ‘drop’]) { |w| w.length }
Output:
“drop”
Create a hash where each element of the array is a key and the value is the when the key is called into the proc.
Modify the hash to only find the key/value pairs where the value matches the maximum value
Then extract just the keys and if there is more than 1 key, use .last to find the one that appears later.
def maximum(arr, &prc) hash = {} arr.map { |e| hash[e] = prc.call(e) } hash.select { |k,v| v == hash.values.max }.keys.last end
How do you get a value associated with a corresponding key in a hash?
hash.fetch(key) will return the value associated with the key
Create a method max_tie_breaker where it accepts an arr, proc, and a block as arguments. It should return the element that has the largest result when passed into the block. When there is a tie, use the proc to break the tie. If there is still a tie after using the proc, return the element that comes first in the array. When the array is empty it should return nil.
Input :
array_1= ['potato', 'swimming', 'cat'] array_2= ['cat', 'bootcamp', 'swimming', 'ooooo'] array_3= ['photo','bottle', 'bother'] length= Proc.new { |s| s.length } o_count= Proc.new { |s| s.count('o') }
Output :
(array_1, o_count, &length) #).to eq(‘swimming’)
(array_2, length, &o_count) #).to eq(‘ooooo’)
(array_2, o_count, &length) #).to eq(‘bootcamp’)
(array_3, o_count, &length) #).to eq(‘bottle’)
def max_tie_breaker(arr, prc1, &prc2) return nil if arr.empty?
block_hash = arr.map.group_by { |e| prc2.call(e) } max_block_values = block_hash.fetch(block_hash.keys.max) if max_block_values.length > 1 new_hash = max_block_values.each.group_by { |e| e = prc1.call(e) } values = new_hash.fetch(new_hash.keys.max) values.first else max_block_values = block_hash.fetch(block_hash.keys.max).first end end
Write a method counted_characters that accepts a string as an argument. The method should return an array containing the characters of the string that appeared more than twice. The characters in the output array should appear in the same order they occur in the input string.
Examples
p counted_characters("that's alright folks") # ["t"] p counted_characters("mississippi") # ["i", "s"] p counted_characters("hot potato soup please") # ["o", "t", " ", "p"] p counted_characters("runtime") # []
- Create a hash using .group_by where the key is the count of characters and the values are the characters.
- filter out the keys that are over 2 by using hash.select to filter out the keys you don’t want and .keys to only extract the keys.
- With the relevant keys in an array, use .map to replace the keys with the associated values. Since characters will be repeated, flatten the array and then pull just the uniques.
def counted_characters(str) hash = str.chars.each.group_by { |char| str.chars.count(char) } keys_over_2 = hash.select { |k,v| k > 2}.keys keys_over_2.map { |k| hash[k] }.flatten.uniq end
Write a method triplet_true? that accepts a string as an argument and returns a boolean indicating whether or not the string contains three of the same character consecutively.
Examples
p triplet_true('caaabb') # true p triplet_true('terrrrrible') # true p triplet_true('runninggg') # true p triplet_true('bootcamp') # false p triplet_true('e') # false
- Create a hash
- Create a while loop to keep track via a count when characters are repeated.
- Save the count as a key and the char as the value only if the count is greater than or equal to 3
- see if the hash.length is greater than 1 or not
def triplet_true(str) hash = {} i = 0 while i < str.length char = str[i] count = 0 while char == str[i] count += 1 i += 1 end hash[count] = char if count >= 3 end hash.length >= 1 end
Write a method conjunct_select that accepts an array and one or more procs as arguments. The method should return a new array containing the elements that return true when passed into all of the given procs.
is_positive = Proc.new { |n| n > 0 } is_odd = Proc.new { |n| n.odd? } less_than_ten = Proc.new { |n| n < 10 }
p conjunct_select([4, 8, -2, 11, 7, -3, 13], is_positive) # [4, 8, 11, 7, 13] p conjunct_select([4, 8, -2, 11, 7, -3, 13], is_positive, is_odd) # [11, 7, 13] p conjunct_select([4, 8, -2, 11, 7, -3, 13], is_positive, is_odd, less_than_ten) # [7]
- Create a hash where each key is an array
- Create a nested loop where the outer loop iterates through the array and inner loop iterates thru the procs
- Every time the proc is true, then create a hash key and shovel “true” into it
- Modify the hash to only include values with the length the same size as the proc length to indicate it passed true of all of them.
- Then extract just the keys from them.
def conjunct_select(arr, *prcs) hash = Hash.new { |h,k| h[k] = [] } arr.each do |e| prcs.each do |prc| hash[e] << "true" if prc.call(e) == true end end hash.select { |k,v| v.length == prcs.length }.keys end
Translate a word in pig latin. if the word begins with a vowel, simply add ‘yay’ to the end of the word (example: ‘eat’->’eatyay’)
if the word begins with a non-vowel, move all letters that come before the word’s first vowel to the end of the word and add ‘ay’ (example: ‘trash’->’ashtray’)
- If the word letter (word.chr) is a vowel than add word + “yay”
- find the index of the first vowel by using =~ regex
def pig_latin(word)
‘AEIOUaeiou’.include?(word.chr) ? word + “yay” : word[word=~/[AEIOUaeiou]/..-1] + word[0…word=~/[AEIOUaeiou]/] + “ay”
end
How can i find the index of the first vowel?
What about the last vowel?
- First vowel use the =~ with regex
2. Last vowel, use word.rindex with regex