Let's say I have a array:
newArray = Array.[]
And then I push some strings in it:
newArray.push 'nil'
newArray.push 'nil2'
newArray.push 'nil3'
Now I make a while loop:
while true
load = gets.chomp
if newArray[].include? load
puts 'That pieace of the Array is loaded'
break
end
end
The part if newArray[].include? load is wrong, I know. But how can I make it so this will work?
Your question is confusing, and your code isn't idiomatic Ruby. Consider writing it like:
new_array = []
new_array << 'nil'
new_array << 'nil2'
new_array << 'nil3'
loop do
load = gets.chomp
if new_array.include? load
puts 'That piece of the Array is loaded'
break
end
end
We use snake_case_for_variables becauseItIsALotEasierToRead.
While we can write Array.new or Array.[], we seldom do. We usually assign [] to a variable instead.
We typically push to an array using <<. It's shorter to type, and visually sets apart what's happening.
Use loop do instead of while true.
I'd actually be more straightforward when defining that array:
new_array = %w[nil nil2 nil3]
And I'd use more mnemonic variable names so the code is more self-documenting:
ary = %w[nil nil2 nil3]
loop do
user_input = gets.chomp
if ary.include? user_input
puts 'That piece of the Array is loaded'
break
end
end
If you want to see if the value entered is part of a string element in the array:
if ary.any? { |s| s[user_input] }
puts 'That piece of the Array is loaded'
break
end
If you want to see if the value entered is the last character of a string element in the array:
if ary.any? { |s| s[-1] == user_input }
or:
if ary.any? { |s| s[/#{ user_input }$/] }
Read the documentation for any? to understand what it's doing.
Related
def removal(arr)
letters ="i"
p arr
new_array = arr.map do |c_word|
c_word.each_char.with_index do |char, index|
if letters.include?(char)
c_word[index] = "*"
end
end
end
p arr #the original array is getting edited? why?
p new_array
end
removal(["hiiiiiigh","git", "training"])
In this code, the original array (arr) in the map method keeps getting edited. I thought that map does not edit the original array. If I needed to edit the original, then I would use .map!
I believe it has something to do with the nested enumerator or a variable reference that I am not seeing. Instead of each_char.with_index, I used a while loop and map would still edit the original array. Why is the original array being edited?
You are actually wrong in (at least) two places:
map is not editing the original array
in fact, the original array is not being edited at all
If you look closely, the array hasn't changed, only the strings inside the array have changed. And it is not map that is doing this, it is String#[]=, which you are calling here:
c_word[index] = "*"
So, you are calling a method that edits strings, and you should not be surprised that your strings are edited!
Think of using:
map as saying "I want to create new data based on existing data"
each as saying "I either want to not change any data, or change existing data"
Having this in mind, what you are doing is using map with array to create new array based on existing one, and then using each to modify characters in existing strings. This is why the strings in the original array end up modified.
To fix this use map twice, first to "create new array based on existing array", and then the second time to "create new string based on existing string". This way the original strings won't get modified.
def removal(arr)
letters ="i"
p arr
new_array = arr.map do |word|
word.chars.map do |char|
letters.include?(char) ? '*' : char
end.join
end
p arr
p new_array
end
removal(["hiiiiiigh","git", "training"]) #=> ["hiiiiiigh", "git", "training"]
# ["hiiiiiigh", "git", "training"]
# ["h******gh", "g*t", "tra*n*ng"]
More practical solution to this problem would be something like this:
def censor(strings, forbidden_chars_string, censor_char = '*')
re = Regexp.union(forbidden_chars_string.chars)
strings.map {|str| str.gsub(re, censor_char) }
end
p ["hiiiiiigh","git", "training"] #=> ["hiiiiiigh", "git", "training"]
p censor(["hiiiiiigh","git", "training"], "i") #=> ["h******gh", "g*t", "tra*n*ng"]
p censor(["hiiiiiigh","git", "training"], "gn", '_') #=> ["hiiiiii_h", "_it", "trai_i__"]
This is happening because inside the map block you are doing some processing on each word of arr and not on each word new_array. If you want to copy the words of arr and change it in new_array then create a copy, change it and return the word.
Checkout these 2 codes and you will get my point
Code 1
def removal(arr)
letters ="i"
p arr
new_array = arr.map do |c_word|
c_word.each_char.with_index do |char, index|
if letters.include?(char)
c_word[index] = "*"
end
end
c_word
end
p arr
p new_array
end
removal(["hiiiiiigh","git", "training"])
Here you are changing words of arr and copying it to new_array
Code 2
def removal(arr)
letters ="i"
p arr
new_array = arr.map do |c_word|
n_word = c_word.dup
n_word.each_char.with_index do |char, index|
if letters.include?(char)
n_word[index] = "*"
end
end
n_word
end
p arr
p new_array
end
removal(["hiiiiiigh","git", "training"])
Here you are copying words of arr, changing it and adding them to new_array
If you don't want to change the array's elements, you should not change them. Your problem is in this line:
c_word[index] = "*"
So just use methods that do not affect the recipient, e.g.:
def removal(array)
letter = 'i'
array.map { |word| word.gsub(letter, '*') }
end
Say I want to puts the alphabet. So I can do something like:
alphabet = ('a'..'z')
alphabet.map do |a|
puts a
end
What I want to do now is exclude the vowels.
alphabet = ('a'..'z')
vowels = ['a','e','i','o','u']
alphabet.map do |a|
puts a unless a == vowels
end
I am trying to avoid this:
alphabet = ('a'..'z')
alphabet.map do |a|
puts a unless a == 'a'
puts a unless a == 'e'
puts a unless a == 'i'
puts a unless a == 'o'
puts a unless a == 'u'
end
How do I syntactically implement the second example so that it works properly?
A Range can be expanded into an Array. Then you can subtract another array.
chars = ('a'..'z').to_a - %w( a e i o u )
chars.each do |a|
puts a
end
As a side note, don't use #map unless you really need to. Use #each if you don't care about the returning value.
You don't want equality, you want inclusion:
puts a if vowels.include? a
Also, you're using map (same as collect) which will actually return the results of the puts statements. Unless you actually need that, use each. Or find the letters that match the condition and use that collection to print the results later.
Use the Array#include? method:
puts a unless vowels.include? a
Source: http://rubydoc.info/stdlib/core/1.9.2/Array#include%3F-instance_method
You can even get rid of the loop. This preserves the original alphabet.
alphabet = ('a'..'z')
puts (alphabet.to_a - %w(a e i o u)).join('\r')
Enumerable#grep would work, too:
('a'..'z').grep(/[^aeiou]/) { |a| puts a }
Or simply
puts ('a'..'z').grep(/[^aeiou]/)
I am currently working on a basic Ruby programming project, that focuses on creating classes, and operations on those classes. I have very little experience, but understand the general idea of Ruby.
My task is making an Array2 class. Creating arrays from the class, perform operations on the arrays. The methods I attempted are a to-string method, and a is-reverse method that has two array parameters, and tests if the first array is the reverse of the second array.
Here is my attempt, I tried but I am having trouble passing the arrays properly into the class. Also I believe that I am having some calling complications.
class Array2
def initialize (a)
#array = Array.new(a)
end
def to_s
return #array
end
def isreverse (array1,array2)
reverasea = Array.new
reverasea = array1.reverse
if (reversea = array2) then
return "The First Array Is The Reverse Of The Second Array"
else
return "The First Array Is Not The Reverse Of The Second Array"
end
end
end
array1 = ["4","5","6","7"]
array2 = ["7","6","5","3"]
a1 = Array2.new(array1)
a2 = Array2.new(array2)
puts a1.to_s
puts a2.to_s
puts a1.isreverse(array1, array2)
You have an assignment where you probably meant equality test:
if (reversea = array2) then
you could dispense with reversea entirely and just test (this requires a reverse method in Array2)
if (array1.reverse == #array) then
I would personally make isreverse a boolean, and eliminate the need to pass in the same array again:
def isreverse? (array1)
return (#array.reverse == array1)
end
then use it like
puts "The First Array Is#{a1.isreverse?(a2)?"":" Not"} The Reverse Of The Second Array"
put it all together and it looks like:
class Array2
def initialize (a)
#array = Array.new(a)
end
def to_s
return #array
end
def reverse
#array.reverse
end
def isreverse? (array1)
return (array1.reverse == #array)
end
end
array1 = ["4","5","6","7"]
array2 = ["7","6","5","3"]
a1 = Array2.new(array1)
a2 = Array2.new(array2)
puts a1.to_s
puts a2.to_s
puts "The First Array Is#{a1.isreverse?(a2)?"":" Not"} The Reverse Of The Second Array"
fiddle
Here are some adjustments to your existing approach. I put in comments where I changed the original::
class Array2
def initialize (a)
#array = Array.new(a)
end
def to_array # to_s is a misnomer: it doesn't return a string
return #array
end
def isreverse (a)
#reverasea = Array.new NOTE this is not needed; the following .reverse creates a new array for you
reversea = a.to_array.reverse # get the reverse of the array represented
# NOTE = is assign, == is compare in this case
# The following compares the reversed of the array `a` with the array value of this class, #array
if (reversea == #array) then
return "The First Array Is The Reverse Of The Second Array"
else
return "The First Array Is Not The Reverse Of The Second Array"
end
end
end
array1 = ["4","5","6","7"]
array2 = ["7","6","5","3"]
a1 = Array2.new(array1)
a2 = Array2.new(array2)
puts a1.to_array # (renamed)
puts a2.to_array # (renamed)
#puts a1.isreverse(array1, array2) NOTE you don't need to pass array1 into class a1 since it is already made from array1
puts a1.isreverse(a2)
I would go for something simpler such as:
Filename: reverser.rb
class Reverser
def self.is_reverse_of(array1,array2)
array1_reversed=array1.reverse
is_or_isnt= (array1_reversed==array2)? 'Not ' : ''
return "The First Array Is #{is_or_isnt}The Reverse Of The Second Array"
end
end
puts Reverser.is_reverse_of(["4","5","6","7"], ["7","6","5","4"])
puts Reverser.is_reverse_of(["4","5","6","7"], ["7","6","5","3"])
ruby reverser.rb
The First Array Is Not The Reverse Of The Second Array
The First Array Is The Reverse Of The Second Array
The idea being to use a class level method and not instantiate as much and have less code.
I am trying to make this code return when called without a block. The uncommented lines at the bottom is what I'm trying to get to return. The first uncommented line should return in tut, second line converted to english and the last should be in english. And why is the line " puts eng " returning up and down and not in sentence form? Thanks for any and all help.
Here's my code:
class Tut
##consonants = ["b","c","d","f","g","h","j","k","l","m","n","p","q","r","s","t","v","w","x","y","z"]
def is_tut? string
if string =~ /^(([b-df-hj-np-z]ut)|([aeiou\s])|[[:punct:]])+$/i
yield
else
false
end
end
def self.to_tut string
string.each_char do |c|
c += "ut" if ##consonants.find { |i| i == c.downcase }
yield c if block_given?
end
end
def self.to_english string
array = string.split //
array.each do |c|
if ##consonants.find { |i| i == c.downcase }
array.shift
array.shift
end
yield c if block_given?
end
end
end
#Tut.to_tut( "Wow! Look at this get converted to Tut!" ) { |c| print c }
# should output : Wutowut! Lutookut atut tuthutisut gutetut cutonutvuteruttutedut tuto Tututut!
#puts
#puts
tut = Tut.to_tut( "Wow! Look at this get converted to Tut!" )
puts "from return: #{tut}"
puts
#Tut.to_tut( "Wutowut! Lutookut atut tuthutisut gutetut cutonutvuteruttutedut tuto Tututut!" ) { |c| print c }
#should outout : Wutowut! Lutookut atut tuthutisut gutetut cutonutvuteruttutedut tuto Tututut!
#puts
#puts
tut = Tut.to_tut( "Wutowut! Lutookut atut tuthutisut gutetut cutonutvuteruttutedut tuto Tututut!" )
puts "from return: #{tut}"
#puts
#tut_string = ""
#Tut.to_tut( "I'm in tut but I want to be in english." ) { |c| tut_string += c }
#puts tut_string
# should output : I'mut inut tututut bututut I wutanuttut tuto bute inut enutgutlutisuthut.
puts
#Tut.to_english( tut_string ){ |c| print c }
# should output : I'm in tut but I want to be in english.
lan = Tut.to_english( tut )
puts lan
(Opening note: You normally don't want to modify an Enumerable object while iterating over it, since that makes it much harder to read the code and debug it.)
Your to_tut doesn't retain your modifications because the "c" block variable is a copy of the string slice, instead of a reference to part of the string (if it were a ref, you'd be able to use << to append; "+=" still wouldn't work because it reassigns rather than changing the ref). That's just how each_char works, since a String doesn't contain references.
If you wanted to modify the string in place, you'd probably have to count backwards and then insert the 'ut' by index via string#[]= . But that's way complicated so I'll present a couple alternates.
Working to_tut #1:
def self.to_tut string
string.chars.map do |c|
yield c if block_given?
# this must be the last expression the block
if ##consonants.find { |i| i == c.downcase }
c + 'ut'
else
c
end
end.join
end
Working to_tut #2 - this is probably the most ruby-ish way to do it:
def self.to_tut string
string.gsub(/[#{##consonants.join}]/i) {|match|
yield match if block_given?
# this must be the last expression in the block
match + 'ut'
}
end
Your to_english doesn't work because array.shift always removes the first element of the array. Instead, you want to track the current index, and remove 2 chars starting from index+1.
Working to_english:
def self.to_english2 string
array = string.split //
array.each_with_index do |c, idx|
if ##consonants.find { |i| i == c.downcase }
array.slice!(idx+1, 2)
end
yield c if block_given?
end
array.join
end
Regarding why your "puts lan" returns one char per line - it's because your to_english returns an array. You'll want to call join to convert it.
The methods to_tut and to_english are giving you wrong answers when used without a block. This happens because ruby always returns the last value evaluated in your method. In your code that will be the result of the string.each_char for to_tut or array.each for to_english. In both cases, the result contains the original input, which is consequently returned and printed.
As to the puts eng, it prints the array returned by array.each of to_english.
I know about Object#tap, which takes a value and returns that value. But is there a method that takes a block and returns the value evaluated by the block?
To improve my code in this answer (which is more complicated than the snippet below), I'd like to change
deck.index("A").tap {|index|
STDERR.puts "Result of indexing for #{"A".inspect} is #{index.inspect}"
}
, which has "A" repeated, into
def my_method(*args)
yield *args
end
deck = ['A', 'B', 'C']
my_method("A") {|value| deck.index(value).tap {|index|
STDERR.puts "Result of indexing for #{value.inspect} is #{index.inspect}"
} }
# Result of indexing for "A" is 0
# => 0
What you're looking for is essentially the equivalent of let in Lisp or OCaml — something that allows you to temporarily bind a value to an identifier without introducing a new variable into the larger scope. There isn't anything that lets you do such a thing with that syntax in Ruby. The equivalent Ruby would be:
lambda {|value| deck.index(value).tap {|index|
STDERR.puts "Result of indexing for #{value.inspect} is #{index.inspect}"
} }.call 'A'
You could of course just write a method like:
def let(*values)
yield *values
end
I think you could solve it with fibers. Something like:
def myfiber
block = lambda{nil}
loop{ block = Fiber.yield(block.call) }
end
f = Fiber.new {myfiber }
f.resume
puts "result: #{f.resume(lambda{1})}"
puts "result: #{f.resume(lambda{5})}"
puts "result: #{f.resume(lambda{2})}"
will result in:
result: 1
result: 5
result: 2