I am very beginner in Ruby and probably the question is too easy but well, I've already spent some time on it and couldn't find a solution.
My Ruby script takes a number (ex 10) and a name (ex Vincent). What I want is to make an array looking like
Vincent0
Vincent1..
Vincent9
I can't figure a way to make it..
def arrayfy(string, number)
arr = []
0.upto(number-1) do |i|
arr << "#{string}#{i}"
end
return arr
end
Update: To add these as variables to the class
class Foo
def arrayfy(string, number)
0.upto(number-1) do |i|
var_string = "##{string}#{i}"
var_symbol = var_string.to_sym
self.instance_variable_set(var_symbol, "")
end
end
end
Array.new(10) {|i| "Vincent#{i}"}
gives you
["Vincent0", "Vincent1", "Vincent2", "Vincent3", "Vincent4", "Vincent5",
"Vincent6", "Vincent7", "Vincent8", "Vincent9"]
The documentation for Array is available at http://www.ruby-doc.org/core/classes/Array.html (googling for Array RDoc will give you the URL).
The bit in the braces ({|i| "Vincent#{i}"}) is called a block. You'll definitely want to learn about them.
Using Array.new with a block (docs):
def create_array(count, name)
Array.new(10) { |i| "#{name}#{i} }
end
Using Enumerable#reduce (docs):
def create_array(count, name)
(0...count).reduce([]) { |m,i| m << "#{name}#{i}" }
end
Or using Enumerable#each_with_object (docs):
def create_array(count, name)
(0...count).each_with_object([]) { |i,a| a << "#{name}#{i}" }
end
Using it:
# Using the array (assigning to variables)
array = create_array(10, 'Vincent') # => ['Vincent0', 'Vincent1', 'Vincent2' ...]
name = array[1] # => 'Vincent1'
Just for the record, a solution in a more functional style:
>> def arrayify(str, n)
.. ([str] * n).zip(0...n).map(&:join)
.. end
#=> nil
>> arrayify('Vincent', 10)
#=> ["Vincent0", "Vincent1", "Vincent2", "Vincent3", "Vincent4", "Vincent5", "Vincent6", "Vincent7", "Vincent8", "Vincent9"]
def array_maker(number, string)
result = []
for i in 0..number do
result << "#{string}#{i}"
end
result
end
Related
I have a method called myFilter that takes in an array, and filters out the elements that don't meet the requirement.
For example.
arr = [4,5,8,9,1,3,6]
answer = myfilter(arr) {|i| i>=5}
this run would return an array with elements 5,8,9,6 since they are all greater than or equal to 5.
How would I preform this? the algorithm is easy, but I don't understand how we take in that condition.
Thank you.
I take for granted you don't want to use select method or similar but you want to understand how blocks work.
def my_filter(arr)
if block_given?
result = []
arr.each { |element| result.push(element) if yield element } # here you use the block passed to this method and execute it with the current element using yield
result
else
arr
end
end
The idiomatic way would be:
def my_filter(arr)
return enum_for(:my_filter, arr) unless block_given?
arr.each_with_object([]) do |e, acc|
acc << e if yield e
end
end
More info on Enumerator::Lazy#enum_for.
you can do
def my_filter(arr, &block)
arr.select(&block)
end
then call
my_filter([1, 2, 3]) { |e| e > 2 }
=> [3]
but instead you can just call select with a block directly :)
I am trying to reverse the words of a string in Ruby, without using the reverse method. I want to implement the known algorithm of:
Reverse the whole string
Reverse each word in the reversed string.
Here is what I have come up with:
class String
def custom_reverse(start, limit)
i_start = start
i_end = limit - 1
while (i_start <= i_end)
tmp = self[i_start]
self[i_start] = self[i_end]
self[i_end] = tmp
i_start += 1
i_end -= 1
end
return self
end
def custom_reverse_words
self.custom_reverse(0, self.size)
i_start = 0
i_end = 0
while (i_end <= self.length)
if (i_end == self.length || self[i_end] == ' ')
self.custom_reverse(i_start, i_end)
i_start += 1
end
i_end += 1
end
end
end
test_str = "hello there how are you"
p test_str.custom_reverse_words
But the results are "yahthello ow ou er ereh"
What am I missing?
The gist of any reverse operation is to iterate over elements in the reverse order of what you'd normally do. That is, where you'd usually use the set (0..N-1) you'd instead go through (N-1..0) or more specifically N-1-i where i is 0..N-1:
class String
def reverse_words
split(/\s+/).map{|w|wl=w.length-1;(0..wl).map{|i|w[wl-i]}.join}.join(' ')
end
end
puts "this is reverse test".reverse_words.inspect
# => "siht si esrever tset"
The same principle can be applied to the words in a given string.
Interview questions of this sort are of highly dubious value. Being "clever" in production code is usually a Very Bad Idea.
Here's one way to reverse an array without using the built-in reverse:
class Array
def reverse
tmp_ary = self.dup
ret_ary = []
self.size.times do
ret_ary << tmp_ary.pop
end
ret_ary
end
end
%w[a b c].reverse # => ["c", "b", "a"]
tmp_ary.pop is the secret. pop removes elements from the end of the array.
The cleanest solution I could think of is:
class Array
def my_reverse
sort_by.with_index {|_, i| -i}
end
end
class String
def words
split(/\W+/)
end
def revert_words
words.my_reverse.join(' ')
end
def revert_each_word
words.map {|w| w.chars.my_reverse.join}.join(' ')
end
end
Once you define a simple and efficient array reverser:
def reverse_array(a)
(a.length / 2).times {|i| a[i],a[-(i+1)] = a[-(i+1)],a[i]}
a
end
You can reverse a sentence pretty straightforwardly:
def reverse_sentence(s)
reverse_array(s.split('')).join.split(" ").map{|w| reverse_array(w.split('')).join}.join(" ")
end
reverse_sentence "Howdy pardner" # => "pardner Howdy"
Here's another way:
class String
def reverse_words
split.inject([]){|str, word| str.unshift word}.join(' ')
end
def reverse_chars
each_char.inject([]){|str, char| str.unshift char}.join('')
end
end
Revised
Carey raises a good point, reverse_chars can be simplified, since string is already an Enumerable:
class String
def reverse_chars
each_char.inject(""){|str, char| str.insert(0, char) }
end
end
How is it possible to chain methods in Ruby when the method calls are specified as an array?
Example:
class String
def bipp(); self.to_s + "-bippity"; end
def bopp(); self.to_s + "-boppity"; end
def drop(); self.to_s + "-dropity"; end
end
## this produces the desired output
##
puts 'hello'.bipp.bopp.drop #=> hello-bippity-boppity-dropity
## how do we produce the same desired output here?
##
methods = "bipp|bopp|drop".split("|")
puts 'world'.send( __what_goes_here??__ ) #=> world-bippity-boppity-droppity
[Note to Ruby purists: stylistic liberties were taken with this example. For notes on preferred usage regarding semicolons, parenthesis, comments and symbols, please feel free to consult Ruby style guides (e.g., https://github.com/styleguide/ruby)]
Try this:
methods = "bipp|bopp|drop".split("|")
result = 'world'
methods.each {|meth| result = result.send(meth) }
puts result
or, using inject:
methods = "bipp|bopp|drop".split("|")
result = methods.inject('world') do |result, method|
result.send method
end
or, more briefly:
methods = "bipp|bopp|drop".split("|")
result = methods.inject('world', &:send)
By the way - Ruby doesn't need semicolons ; at the end of each line!
methods = "bipp|bopp|drop".split("|")
result = 'world'
methods.each {|meth| result = result.method(meth).call }
puts result #=> world-bippity-boppity-dropity
or
methods = "bipp|bopp|drop".split("|")
methods.each_with_object('world') {|meth,result| result.replace(result.method(meth).call)} #=> world-bippity-boppity-dropity
For example, the words "stack", I want to get an array like:
['s', 'st', 'sta', ... 'stack', 't', 'ta', ... , 'c', 'ck', 'k']
I did this by such code:
def split_word(str)
result = []
chas = str.split("")
len = chas.size
(0..len-1).each do |i|
(i..len-1).each do |j|
result.push(chas[i..j].join)
end
end
result.uniq
end
Is there better and clean way to do that? Thanks.
def split_word s
(0..s.length).inject([]){|ai,i|
(1..s.length - i).inject(ai){|aj,j|
aj << s[i,j]
}
}.uniq
end
And you can also consider using Set instead of Array for the result.
PS: Here's another idea, based on array product:
def split_word s
indices = (0...s.length).to_a
indices.product(indices).reject{|i,j| i > j}.map{|i,j| s[i..j]}.uniq
end
I'd write:
def split_word(s)
0.upto(s.length - 1).flat_map do |start|
1.upto(s.length - start).map do |length|
s[start, length]
end
end.uniq
end
groups = split_word("stack")
# ["s", "st", "sta", "stac", "stack", "t", "ta", "tac", "tack", "a", "ac", "ack", "c", "ck", "k"]
It's usually more clear and more compact to use map (functional) instead of the pattern init empty + each + append + return (imperative).
def substrings(str)
output = []
(0...str.length).each do |i|
(i...str.length).each do |j|
output << str[i..j]
end
end
output
end
this is just a cleaned up version of your method and it works with less steps =)
Don't think so.
Here's my attempted version:
def split_word(str)
length = str.length - 1
[].tap do |result|
0.upto(length) do |i|
length.downto(i) do |j|
substring = str[i..j]
result << substring unless result.include?(substring)
end
end
end
end
def substrings(str)
(0...str.length).map do |i|
(i...str.length).each { |j| str[i..j]}
end
end
Just another way to do it, that reads a little clearer to me.
Here is the recursive way to get all the possible sub strings.
def substrings str
return [] if str.size < 1
((0..str.size-1).map do |pos|
str[0..pos]
end) + substrings(str[1..])
end
Way later, but this is what I got from reformatting your code a bit.
def substrings(string)
siz = string.length
answer = []
(0..siz-1).each do |n|
(n..siz-1).each do |i|
answer << string[n..i]
end
end
answer
end
I want to convert something like this:
class NestedItem
attr_accessor :key, :children
def initialize(key, &block)
self.key = key
self.children = []
self.instance_eval(&block) if block_given?
end
def keys
[key] + children.keys
end
end
root = NestedItem.new("root") do
children << NestedItem.new("parent_a") do
children << NestedItem.new("child_a")
children << NestedItem.new("child_c")
end
children << NestedItem.new("parent_b") do
children << NestedItem.new("child_y")
children << NestedItem.new("child_z")
end
end
require 'pp'
pp root
#=>
# #<NestedItem:0x1298a0
# #children=
# [#<NestedItem:0x129814
# #children=
# [#<NestedItem:0x129788 #children=[], #key="child_a">,
# #<NestedItem:0x12974c #children=[], #key="child_c">],
# #key="parent_a">,
# #<NestedItem:0x129738
# #children=
# [#<NestedItem:0x129698 #children=[], #key="child_y">,
# #<NestedItem:0x12965c #children=[], #key="child_z">],
# #key="parent_b">],
# #key="root">
Into this:
root.keys #=>
[
"root",
"root.parent_a",
"root.parent_a.child_a",
"root.parent_a.child_c",
"root.parent_b",
"root.parent_b.child_y",
"root.parent_b.child_z",
]
...using a recursive method.
What's the simplest way to go about this?
Update
I did this:
def keys
[key] + children.map(&:keys).flatten.map do |node|
"#{key}.#{node}"
end
end
Anything better?
Would Array.flatten work for you?
self.children.flatten should return the flattened results.
Yes, .flatten will produce what I think you really want.
But if you want exactly the string output you typed, this will do it:
def keys x
here = key
here = x + '.' + here if x
[ here ] + children.inject([]) { |m,o| m += o.keys here }
end
pp root.keys nil
Or, alternatively, replace the last line in #keys with:
([ here ] + children.map { |o| o.keys here }).flatten