Simplify Ruby conditional involving regex and two vars? - ruby

The goal is to Rubify (ie. use some Ruby magic) the so commented code.
I'm learning Ruby and it seems every time I write a bit of code, Ruby has some magic that can simplify and make it more readable.
For example (and unrelated to the code below), instead of writing a loop to iterate over an array of integers to get the sum, in Ruby, sum = array.inject(:+) works magic.
string = 'abcd'
inn = ''
out = ''
letters = 'az'
# Rubify below, por favor
letters.split('').each do |l|
if string[/#{l}/i]
inn << l
else
out << l
end
end
Ideas?

string = 'abcd'
letters = 'az'
inn, out = letters.chars.partition{|char| string.include?(char)}.map!(&:join)

Related

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

Swap adjacent elements in array

I am trying to build a method in Ruby that will take in a string that has been split into an array of letters and then iterate through the array, swapping the element at index n with that at index n+1. The method will then join the new array into a string and push it to another array.
Here is an example of what I am looking to do:
string = "teh"
some_method(string)
some ruby magic here
array << new_string
end
Expected output:
["eth", "the"]
This is for a spell checker program I am writing for school. The method will check if letters in a misspelled word are swapped by checking to see if the output array elements are in the dictionary. If they are, it will return the word with that is most likely the correct word. I haven't had any luck finding articles or documentation on how to build such a method in ruby or on an existing method to do this. I've been tinkering with building this method for awhile now but my code isn't behaving anything like what I need. Thanks in advance!
As #Sergio advised, you want to use parallel assignment for this:
def reverse_em(str)
(0...str.size-1).map do |i|
s = str.dup
s[i], s[i+1] = s[i+1], s[i]
s
end
end
candidates = reverse_em "alogrithm"
#=> ["laogrithm", "aolgrithm", "algorithm", "alorgithm",
# "alogirthm", "alogrtihm", "alogrihtm", "alogritmh"]
dictionary_check(candidates)
#=> algorithm
# al·go·rithm
# noun \ˈal-gə-ˌri-thəm\
# a set of steps that are followed in order to solve a
# mathematical problem or to complete a computer process
Without splitting it into arrays then joining to new arrays (because that doesn't seem necessary):
def some_method(string)
swapped_strings = []
(0...string.size-1).each do |i|
temp_string = string.dup
temp_string[i], temp_string[i+1] = temp_string[i+1], temp_string[i]
swapped_strings << temp_string
end
swapped_strings
end

How do I make multiple combinations with a string in ruby?

Input should be a string:
"abcd#gmail.com"
Output should be an Array of strings:
["abcd#gmail.com",
"a.bcd#gmail.com",
"ab.cd#gmail.com",
"abc.d#gmail.com",
"a.b.cd#gmail.com",
"a.bc.d#gmail.com",
"a.b.c.d#gmail.com"]
The idea: "Make every possible combination in the first string part ("abcd") with a dot. Consecutive dots are not allowed. There are no dots allowed in the beginning and in the end of the first string part ("abcd")"
This is what I've came up with so far:
text,s = "abcd".split""
i=0
def first_dot(text)
text.insert 1,"."
end
def set_next_dot(text)
i = text.rindex(".")
text.delete_at i
text.insert(i+1,".")
end
My approach was
write a function, that sets the first dot
write a function that sets the next dot
...(magic)
I do not know how to put the pieces together. Any Idea? Or perhaps a better way?
thanx in advance
edit:
I think I found the solution :)
I will post it in about one hour (it's brilliant -> truth tables, binary numbers, transposition)
...and here the solution
s = "abc"
states = s.length
possibilites = 2**states
def set_space_or_dot(value)
value.gsub("0","").gsub("1",".")
end
def fill_with_leading_zeros(val, states)
if val.length < states
"0"*(states-val.length)+val
else
val
end
end
a = Array.new(possibilites,s)
a = a.map{|x| x.split ""}
b = [*0...possibilites].map{|x| x.to_s(2).to_s}
b = b.map{|x| fill_with_leading_zeros x,states}
b = b.map{|x| x.split ""}
c = []
for i in 0 ... a.size
c[i] = (set_space_or_dot (a[i].zip b[i]).join).strip
end
Changing pduersteler answer a little bit:
possibilities = []
string = "abcd#example.com"
(string.split('#')[0].size-1).times do |pos|
possibility = string.dup
possibilities << possibility.insert(pos+1, '.')
end
How about this (probably needs a bit more fine-tuning to suit your needs):
s = "abcd"
(0..s.size-1).map do |i|
start, rest = [s[0..i], s[(i+1)..-1]]
(0..rest.size-1).map { |j| rest.dup.insert(j, '.') }.map { |s| "#{start}#{s}"}
end.flatten.compact
#=> ["a.bcd", "ab.cd", "abc.d", "ab.cd", "abc.d", "abc.d"]
An option would be to iterate n times through your string moving the dot, where n is the amount of chars minus 1. This is what you're doing right now, but without defining two methods.
Something like this:
possibilities = []
string = "abcd#example.com"
(string.split('#')[0].size-1).times do |pos|
possibilities << string.dup.insert(pos+1, '.')
end
edit
Now tested. THanks to the comments, you need to call .dup on the string before the insert. Otherwise, the dot gets inserted into the string and will stay there for each iteration causing a mess. Calling .dup onthe string will copy the string and works on the copy instead, leaving the original string untouched.

Reversing a string in a weird way

I am attempting to reverse a string without using the reverse function, classes and arrays. However I am trying to do it with regular expressions. I use Programmers Notepad to write programs. When I run the below given code, it is not displaying any result. I am trying to insert a period(.) in the seventh or eighth position on each loop to fetch the next character in reverse order.
s = "This is to test reverse of a string"
len = s.length
for j in len..1 do
mycommand = "s.scan(/.$/) {|x| puts x}"
mycommand = mycommand.insert 7,"."
end
well, it's not absolutely clear what you're trying to do, but here're some points:
since you declare 'mycommand' variable in a loop(block) - it will be only visible in block. Meaning, you won't be able to use it anywhere else. And as it is now - "mycommand" variable will be created on every iteration
here: for j in len..1 do your 'len' variable (35) is more then 1. Iteration won't happen, you should use it like
for j in 1..len do
here:
mycommand = "s.scan(/.$/) {|x| puts x}"
you declare mycommand as a string( just a set of characters )
so, when you then state:
mycommand = mycommand.insert 7,"."
ruby will just transform your string as follows: "s.scan(./.$/) {|x| puts x}"
The concept isn't absolutely clear, but I think what you're trying to do is:
s = "This is to test reverse of a string"
len = s.length
mycommand = "s.scan(/.$/) {|x| print x}" # This does not execute a command, you just create a string
for j in len..1 do
eval mycommand # Now this executes your command. Take a time and google for "ruby eval"
s.chop! # This removes last character from your string. e.g 'hello'.chop! #=> 'hell'
end
You can't use downto for. There is downto method for this job. I don't exactly understand what you want from this line mycommand = mycommand.insert 7,"." but it reverses string too:
s = "This is to test reverse of a string"
len = s.length
len.downto(1) do |j|
s.scan(/.$/) {|x| puts x}
s.chop!
end
s="abc"
(s.size-1).downto(0).map{|x|s[x]}.join
The following 1 liner will do the trick:
> "test reverse of a string".scan(/./).inject([]) {|n,v| n.unshift v}.join
=> "gnirts a fo esrever tset"
or more succinctly:
> "test reverse of a string".scan(/./).inject("") {|n,v| n = v + n}
=> "gnirts a fo esrever tset"
This reverses the string based on your requirements.
I didn't grok the last part of your question about inserting between the 7th and 8th positions so I didn't attempt to answer that part.

(Ruby) Converting string values into assignable properties for OpenStructs...?

I've got a bit of an odd situation. If I were using a hash, this issue would be easy, however, I'm trying to use "OpenStruct" in Ruby as it provides some decently cool features.
Basically, I think I need to "constantize" a return value. I've got a regular expression:
textopts = OpenStruct.new()
textopts.recipients = []
fileparts = fhandle.read.split("<<-->>")
fileparts[0].chomp.each{|l|
if l =~ /Recipient.*/i
textopts.recipients << $&
elsif l =~ /(ServerAddress.*|EmailAddress.*)/i
textopts.$& = $&.split(":")[1]
end
}
I need a way to turn the $& for "textopts" into a valid property for filling. I've tried "constantize" and some others, but nothing works. I would assume this is possible, but perhaps I'm wrong. Obviously if I were using a hash I could just do "textopts[$&] = .....".
Any ideas?
Keeping the structure of your solution, this is one way to do it:
textopts = OpenStruct.new(:recipients => [])
fileparts = fhandle.read.split('<<-->>')
fileparts.first.chomp.each_line do |l|
case l
when /Recipient.*/i
textopts.recipients << $&
when /(Server|Email)Address.*/i
textopts.send "#{$&}=", $&.split(':')[1]
end
end
But I can't help but think that this should be a proper parser.

Resources