Join a ruby enumerator into a string - ruby

I have an instance of Enumerator::Generator that yields strings. I need to join them into a single string.
What's a good way of doing this? I notice that * doesn't work. I know I can .map {|x| x} first but that seems rather un-idiomatic

I think in this case I' might reach for inject/reduce (aliases for the same method, reduce as a name makes more sense, to me) with the + operator:
enum.reduce(:+)
# or, passing in a block
enum.reduce(&:+)
As a full example:
# never used Enumerator::Generator directly, but you called it out specifically
# in your question, and this seems to be doing the trick to get it working
enum = Enumerator::Generator.new do |y|
y.yield "ant"
y.yield "bear"
y.yield "cat"
end
p enum.reduce(&:+) # output: "antbearcat"
# crude example of modifying the strings as you join them
p enum.reduce('') { |memo, word| memo += word.upcase + ' ' }
# output: "ANT BEAR CAT "

a=["Raja","gopalan"].to_enum #let's assume this is your enumerator
Write the following code
p a.map(&:itself).join
Or
p a.to_a.join
output
"Rajagopalan"

Related

How to use reduce/inject in Ruby without getting Undefined variable

When using an accumulator, does the accumulator exist only within the reduce block or does it exist within the function?
I have a method that looks like:
def my_useless_function(str)
crazy_letters = ['a','s','d','f','g','h']
str.split.reduce([]) do |new_array, letter|
for a in 0..crazy_letters.length-1
if letter == crazy_letters[a]
new_array << letter
end
end
end
return true if (new_array == new_array.sort)
end
When I execute this code I get the error
"undefined variable new_array in line 11 (the return statement)"
I also tried assigning the new_array value to another variable as an else statement inside my reduce block but that gave me the same results.
Can someone explain to me why this is happening?
The problem is that new_array is created during the call to reduce, and then the reference is lost afterwards. Local variables in Ruby are scoped to the block they are in. The array can be returned from reduce in your case, so you could use it there. However, you need to fix a couple things:
str.split does not break a string into characters in Ruby 2+. You should use str.chars, or str.split('').
The object retained for each new iteration of reduce must be retained by returning it from the block each time. The simplest way to do this is to put new_array as the last expression in your block.
Thus:
def my_useless_function(str)
crazy_letters = ['a','s','d','f','g','h']
crazy_only = str.split('').reduce([]) do |new_array, letter|
for a in 0..crazy_letters.length-1
if letter == crazy_letters[a]
new_array << letter
end
end
new_array
end
return true if (crazy_only == crazy_only.sort)
end
Note that your function is not very efficient, and not very idiomatic. Here's a shorter version of the function that is more idiomatic, but not much more efficient:
def my_useless_function(str)
crazy_letters = %w[a s d f g h]
crazy_only = str.chars.select{ |c| crazy_letters.include?(c) }
crazy_only == crazy_only.sort # evaluates to true or false
end
And here's a version that's more efficient:
def efficient_useless(str)
crazy_only = str.scan(/[asdfgh]/) # use regex to search for the letters you want
crazy_only == crazy_only.sort
end
Block local variables
new_array doesn't exist outside the block of your reduce call. It's a "block local variable".
reduce does return an object, though, and you should use it inside your method.
sum = [1, 2, 3].reduce(0){ |acc, elem| acc + elem }
puts sum
# 6
puts acc
# undefined local variable or method `acc' for main:Object (NameError)
Your code
Here's the least amount of change for your method :
def my_useless_function(str)
crazy_letters = ['a','s','d','f','g','h']
new_array = str.split(//).reduce([]) do |new_array, letter|
for a in 0..crazy_letters.length-1
if letter == crazy_letters[a]
new_array << letter
end
end
new_array
end
return true if (new_array == new_array.sort)
end
Notes:
return isn't needed at the end.
true if ... isn't needed either
for loop should never be used in Ruby
reduce returns the result of the last expression inside the block. It was for in your code.
If you always need to return the same object in reduce, it might be a sign you could use each_with_object.
"test".split is just ["test"]
String and Enumerable have methods that could help you. Using them, you could write a much cleaner and more efficient method, as in #Phrogz answer.

Reversing a Ruby String, without .reverse method

I am working on this coding challenge, and I have found that I am stuck. I thought it was possible to call the .string method on an argument that was passed in, but now I'm not sure. Everything I've found in the Ruby documentation suggests otherwise. I'd really like to figure this out without looking at the solution. Can someone help give me a push in the right direction?
# Write a method that will take a string as input, and return a new
# string with the same letters in reverse order.
# Don't use String's reverse method; that would be too simple.
# Difficulty: easy.
def reverse(string)
string_array = []
string.split()
string_array.push(string)
string_array.sort! { |x,y| y <=> x}
end
# These are tests to check that your code is working. After writing
# your solution, they should all print true.
puts(
'reverse("abc") == "cba": ' + (reverse("abc") == "cba").to_s
)
puts(
'reverse("a") == "a": ' + (reverse("a") == "a").to_s
)
puts(
'reverse("") == "": ' + (reverse("") == "").to_s
)
This is the simplest one line solution, for reversing a string without using #reverse, that I have come across -
"string".chars.reduce { |x, y| y + x } # => "gnirts"
Additionally, I have never heard of the #string method, I think you might try #to_s.
Easiest way to reverse a string
s = "chetan barawkar"
b = s.length - 1
while b >= 0
print s[b]
b=b-1
end
You need to stop the search for alternative or clever methods, such as altering things so you can .sort them. It is over-thinking the problem, or in some ways avoiding thinking about the core problem you have been asked to solve.
What this test is trying to get you you to do, is understand the internals of a String, and maybe get an appreciation of how String#reverse might be implemented using the most basic string operations.
One of the most basic String operations is to get a specific character from the string. You can get the first character by calling string[0], and in general you can get the nth character (zero-indexed) by calling string[n].
In addition you can combine or build longer strings by adding them together, e.g. if you had a="hell" and b="o", then c = a + b would store "hello" in the variable c.
Using this knowledge, find a way to loop through the original string and use that to build the reverse string, one character at a time. You may also need to look up how to get the length of a string (another basic string method, which you will find in any language's string library), and how to loop through numbers in sequence.
You're on the right track converting it to an array.
def reverse(str)
str.chars.sort_by.with_index { |_, i| -i }.join
end
Here is a solution I used to reverse a string without using .reverse method :
#string = "abcde"
#l = #string.length
#string_reversed = ""
i = #l-1
while i >=0 do
#string_reversed << #string[i]
i = i-1
end
return #string_reversed
Lol, I am going through the same challenge. It may not be the elegant solution, but it works and easy to understand:
puts("Write is a string that you want to print in reverse")
#taking a string from the user
string = gets.to_s #getting input and converting into string
def reverse(string)
i = 0
abc = [] # creating empty array
while i < string.length
abc.unshift(string[i]) #populating empty array in reverse
i = i + 1
end
return abc.join
end
puts ("In reverse: " + reverse(string))
Thought i'd contribute my rookie version.
def string_reverse(string)
new_array = []
formatted_string = string.chars
new_array << formatted_string.pop until formatted_string.empty?
new_array.join
end
def reverse_str(string)
# split a string to create an array
string_arr = string.split('')
result_arr = []
i = string_arr.length - 1
# run the loop in reverse
while i >=0
result_arr.push(string_arr[i])
i -= 1
end
# join the reverse array and return as a string
result_arr.join
end

odd usage of "end" in Sample code

Looking through this I notice something I have never seen before on line 83.end.map(&:chomp) so end is an object? (I realize that might be 100% wrong.) Can someone explain what and how that works there? What exactly is advantage?
No, end is not an object, but object.some_method do ... end is an object (or rather it's evaluated to an object) - namely the object returned by the some_method method.
So if you do object.some_method do ... end.some_other_method, you're calling some_other_method on the object returned by some_method.
The full code snippet you're referring to is below:
def initialize(dict_file)
#dict_arr = File.readlines(dict_file).select do |word|
!word.include?("-") && !word.include?("'")
end.map(&:chomp)
end
notice that the end you're talking about is the end of the block that starts on the 2nd line (it matches the do on line 2).
Perhaps if you see it parenthesized, and rewritten with curly braces, it will make more sense:
def initialize(dict_file)
#dict_arr = (File.readlines(dict_file).select { |word|
!word.include?("-") && !word.include?("'")
}).map(&:chomp)
end
It's often helpful to examine what Ruby is doing, step-by-step. Let's see what's going with the method ComputerPlayer#initialize:
def initialize(dict_file)
#dict_arr = File.readlines(dict_file).select do |word|
!word.include?("-") && !word.include?("'")
end.map(&:chomp)
end
First, create a file:
File.write("my_file", "cat\ndog's\n")
When we execute:
ComputerPlayer.new("my_file")
the class method IO#readlines is sent to File, which returns an array a:
a = File.readlines("my_file")
#=> ["cat\n", "dog's\n"]
Enumerable#select is sent to the array a to create an enumerator:
b = a.select
#=> #<Enumerator: ["cat\n", "dog's\n"]:select>
We can convert this enumerator to an array to see what it will pass to it's block:
b.to_a
=> ["cat\n", "dog's\n"]
The enumerator is invoked by sending it the method each with a block, and it returns an array c:
c = b.each { |word| !word.include?("-") && !word.include?("'") }
#=> ["cat\n"]
Lastly, we send Enumerable#map with argument &:chomp (the method String#chomp converted to a proc) to the array c:
c.map(&:chomp)
#=> ["cat"]
A final point: you can improve clarity by minimizing the use of !. For example, instead of
...select do |word|
!word.include?("-") && !word.include?("'")
consider
...reject do |word|
word.include?("-") || word.include?("'")
You might also use a regex.

Ruby: how does one print a 2D array?

puts WINNING_ROWS.each{ |solution| "[ #{solution.map{ |space| "#{space}"}} ]"}
I tried doing the above, but it just lists each value with a new line char afterwards.
I'm trying to get the output:
[stuff,in,row,1]
[stuff,in,row,2]
etc
If this is just for debugging, the usual way is to say either
p expression
or
puts expression.inspect
...which is about the same thing.
You can also use pp.
require 'pp'
pp expression
pp(expr)
One could do something like this:
WINNING_ROWS = [[1,2,3],[4,5,6]]
WINNING_ROWS.map { |x| x.inspect }.join("")
Which will get you a string formatted as you requested
You're relying on the default to_s of Array. #each returns the array itself. So what you're doing is the same as puts WINNING_ROWS. Also, keep in mind that puts adds a newline at the end, so if you don't want that you have to use write (which is not available in the Kernel module like puts is, so you must call it directly on your STDOUT output).
You probably want something like:
WINNING_ROWS = [[1,2,3],[4,5,6]]
WINNING_ROWS.each {|row| STDOUT.write row.inspect }
=> [1, 2, 3][4, 5, 6]
# or this may work for you as well
# STDOUT.write WINNING_ROWS.inspect

Automatic counter in Ruby for each?

I want to use a for-each and a counter:
i=0
for blah in blahs
puts i.to_s + " " + blah
i+=1
end
Is there a better way to do it?
Note: I don't know if blahs is an array or a hash, but having to do blahs[i] wouldn't make it much sexier. Also I'd like to know how to write i++ in Ruby.
Technically, Matt's and Squeegy's answer came in first, but I'm giving best answer to paradoja so spread around the points a bit on SO. Also his answer had the note about versions, which is still relevant (as long as my Ubuntu 8.04 is using Ruby 1.8.6).
Should've used puts "#{i} #{blah}" which is a lot more succinct.
As people have said, you can use
each_with_index
but if you want indices with an iterator different to "each" (for example, if you want to map with an index or something like that) you can concatenate enumerators with the each_with_index method, or simply use with_index:
blahs.each_with_index.map { |blah, index| something(blah, index)}
blahs.map.with_index { |blah, index| something(blah, index) }
This is something you can do from ruby 1.8.7 and 1.9.
[:a, :b, :c].each_with_index do |item, i|
puts "index: #{i}, item: #{item}"
end
You can't do this with for. I usually like the more declarative call to each personally anyway. Partly because its easy to transition to other forms when you hits the limit of the for syntax.
Yes, it's collection.each to do loops, and then each_with_index to get the index.
You probably ought to read a Ruby book because this is fundamental Ruby and if you don't know it, you're going to be in big trouble (try: http://poignantguide.net/ruby/).
Taken from the Ruby source code:
hash = Hash.new
%w(cat dog wombat).each_with_index {|item, index|
hash[item] = index
}
hash #=> {"cat"=>0, "wombat"=>2, "dog"=>1}
If you don't have the new version of each_with_index, you can use the zip method to pair indexes with elements:
blahs = %w{one two three four five}
puts (1..blahs.length).zip(blahs).map{|pair|'%s %s' % pair}
which produces:
1 one
2 two
3 three
4 four
5 five
As to your question about doing i++, well, you cannot do that in Ruby. The i += 1 statement you had is exactly how you're supposed to do it.
If you want to get index of ruby for each, then you can use
.each_with_index
Here is an example to show how .each_with_index works:
range = ('a'..'z').to_a
length = range.length - 1
range.each_with_index do |letter, index|
print letter + " "
if index == length
puts "You are at last item"
end
end
This will print:
a b c d e f g h i j k l m n o p q r s t u v w x y z You are at last item
The enumerating enumerable series is pretty nice.
If blahs is a class that mixes in Enumerable, you should be able to do this:
blahs.each_with_index do |blah, i|
puts("#{i} #{blah}")
end

Resources