Related
I am trying to find the index of the first and second instance of a string variable. I want to be able to use any predefined string variable but when I try to do that it gives me an error. I want to be able to declare multiple string variables like ss, aa, ff, etc and use them in place of xx. Can someone help me out?
#aa is a predefined array
xx = "--help--"
find_xx_instance = aa.each_with_index.select{|i,idx| i =~ /xx/}
#/--help--/works but not /xx/
find_xx_instance.map! {|i| i[1]}
#gives me info between the first two instances of string
puts aa[find_xx_instance[0]+1..find_xx_instance[1]-1]
As far as I understand, you just need to pass variable to regular expression. Try this:
find_xx_instance = aa.each_with_index.select{|i,idx| i =~ /#{xx}/}
I have assumed you are given an array of strings, arr, a string str, and an integer n, and wish to return an array a of n elements i, where i is the index of the ith+1 instance of str in arr.
For example:
arr = %w| Now is the time for the Zorgs to attack the Borgs |
#=> ["Now", "is", "the", "time", "for", "the", "Zorgs", "to", "attack", "the", "Borgs"]
str = "the"
nbr = 2
This is one way:
b = arr.each_index.select { |i| arr[i]==str }
#=> [2, 5, 9]
b.first(nbr)
#=> [2, 5]
which can be written
arr.each_index.select { |i| arr[i]==str }.first(nbr)
This For small problems like this one, that's fine, but if arr is large, it would be better to terminate the calculations after nbr instances of str have been found. We can do that by creating a Lazy enumerator:
arr.each_index.lazy.select { |i| arr[i]==str }.first(nbr)
#=> [2, 5]
Here's a second example that clearly illustrates that lazy is stopping the calculations after nbr strings str in arr have been found:
(0..Float::INFINITY).lazy.select { |i| arr[i] == str }.first(nbr)
#=> [2, 5]
I am given a hash with values as an array of integers. I want to add all values of same index in my result. The length of all arrays in hash values is same.
For ex,
hash = {
"A" => [1,2,3],
"B" => [1,2,3],
"C" => [1,2,3]
}
Then the resultant array i want,adding all same index elements together will be [3,6,9].
Is there any efficient way to do this in ruby ?? Or looping over the keys and array elements is the best possible solution ??
Thanks.
Here's one way:
hash.values.transpose.map { |r| r.reduce(:+) }
#=> [3,6,9]
Another would be:
values = hash.values
values.shift.zip(*values).map { |r| r.reduce(:+) }
#=> [3,6,9]
If you'd prefer using using linear algebra, you could do this:
require 'matrix'
(Matrix.row_vector([1]*hash.size)*Matrix[*hash.values]).row(0).to_a
#=> [3, 6, 9]
I've read % notation but I could not find the explanation about the followings.
Example 1: The following code with % outputs i. Obviously % changes i to a string. But I am not sure what actually % is doing.
irb(main):200:0> [[1,2,3],[4,5,6]].each{ |row| p row.map{ |i| % i } }
["i", "i", "i"]
["i", "i", "i"]
=> [[1, 2, 3], [4, 5, 6]]
irb(main):201:0> [[1,2,3],[4,5,6]].each{ |row| p row.map{ |i| i } }
[1, 2, 3]
[4, 5, 6]
=> [[1, 2, 3], [4, 5, 6]]
Example 2: It seems %2d adding 2 spaces in front of a number. Again, I am not sure what %2d is doing.
irb(main):194:0> [[1,2,3],[4,5,6],[7,8,9]].each{ |row| p row.map{|i| "%2d" % i } }
[" 1", " 2", " 3"]
[" 4", " 5", " 6"]
[" 7", " 8", " 9"]
=> [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
Where can I find the documentation about these?
Here is the doc - You may also create strings using %:.
There are two different types of % strings %q(...) behaves like a single-quote string (no interpolation or character escaping) while %Q behaves as a double-quote string.....
In your first example p row.map{|i| % i } as per the above doc % i creates a string "i".
Examples :-
[1, 2, 3].map { |i| % i } # => ["i", "i", "i"]
% i # => "i"
Just remember as doc is saying -
Any combination of adjacent single-quote, double-quote, percent strings will be concatenated as long as a percent-string is not last.
From the wikipedia link
Any single non-alpha-numeric character can be used as the delimiter, %[including these], %?or these?,...
Now in your case it is %<space>i<space>. Which in the link I mentioned just above are %[..], %?..? etc.. That is why %<space>i<space> gives "i". (I used <space> to show there is a space)
Read Kernel#format
Returns the string resulting from applying format_string to any additional arguments. Within the format string, any characters other than format sequences are copied to the result.
The syntax of a format sequence is follows.
%[flags][width][.precision]type
A format sequence consists of a percent sign, followed by optional flags, width, and precision indicators, then terminated with a field type character. The field type controls how the corresponding sprintf argument is to be interpreted, while the flags modify that interpretation.
Your last question actually points to a method str % arg → new_str.
If IRB made you fool, like made me while trying to understand % i, don't worry, have a look - why in IRB modulo string literal(%) is behaving differently ?. Good answer Matthew Kerwin is given there.
DESCRIPTION:
The purpose of my code is to take in input of a sequence of R's and C's and to simply store each number that comes after the character in its proper array.
For Example: "The input format is as follows: R1C4R2C5
Column Array: [ 4, 5 ] Row Array: [1,2]
My problem is I am getting the output like this:
[" ", 1]
[" ", 4]
[" ", 2]
[" ", 5]
**How do i get all the Row integers following R in one array, and all the Column integers following C in another seperate array. I do not want to create multiple arrays, Rather just two.
Help!
CODE:
puts 'Please input: '
input = gets.chomp
word2 = input.scan(/.{1,2}/)
col = []
row = []
word2.each {|a| col.push(a.split(/C/)) if a.include? 'C' }
word2.each {|a| row.push(a.split(/R/)) if a.include? 'R' }
col.each do |num|
puts num.inspect
end
row.each do |num|
puts num.inspect
end
x = "R1C4R2C5"
col = []
row = []
x.chars.each_slice(2) { |u| u[0] == "R" ? row << u[1] : col << u[1] }
p col
p row
The main problem with your code is that you replicate operations for rows and columns. You want to write "DRY" code, which stands for "don't repeat yourself".
Starting with your code as the model, you can DRY it out by writing a method like this to extract the information you want from the input string, and invoke it once for rows and once for columns:
def doit(s, c)
...
end
Here s is the input string and c is the string "R" or "C". Within the method you want
to extract substrings that begin with the value of c and are followed by digits. Your decision to use String#scan was a good one, but you need a different regex:
def doit(s, c)
s.scan(/#{c}\d+/)
end
I'll explain the regex, but let's first try the method. Suppose the string is:
s = "R1C4R2C5"
Then
rows = doit(s, "R") #=> ["R1", "R2"]
cols = doit(s, "C") #=> ["C4", "C5"]
This is not quite what you want, but easily fixed. First, though, the regex. The regex first looks for a character #{c}. #{c} transforms the value of the variable c to a literal character, which in this case will be "R" or "C". \d+ means the character #{c} must be followed by one or more digits 0-9, as many as are present before the next non-digit (here a "R" or "C") or the end of the string.
Now let's fix the method:
def doit(s, c)
a = s.scan(/#{c}\d+/)
b = a.map {|str| str[1..-1]}
b.map(&:to_i)
end
rows = doit(s, "R") #=> [1, 2]
cols = doit(s, "C") #=> [4, 5]
Success! As before, a => ["R1", "R2"] if c => "R" and a =>["C4", "C5"] if c => "C". a.map {|str| str[1..-1]} maps each element of a into a string comprised of all characters but the first (e.g., "R12"[1..-1] => "12"), so we have b => ["1", "2"] or b =>["4", "5"]. We then apply map once again to convert those strings to their Fixnum equivalents. The expression b.map(&:to_i) is shorthand for
b.map {|str| str.to_i}
The last computed quantity is returned by the method, so if it is what you want, as it is here, there is no need for a return statement at the end.
This can be simplified, however, in a couple of ways. Firstly, we can combine the last two statements by dropping the last one and changing the one above to:
a.map {|str| str[1..-1].to_i}
which also gets rid of the local variable b. The second improvement is to "chain" the two remaining statements, which also rids us of the other temporary variable:
def doit(s, c)
s.scan(/#{c}\d+/).map { |str| str[1..-1].to_i }
end
This is typical Ruby code.
Notice that by doing it this way, there is no requirement for row and column references in the string to alternate, and the numeric values can have arbitrary numbers of digits.
Here's another way to do the same thing, that some may see as being more Ruby-like:
s.scan(/[RC]\d+/).each_with_object([[],[]]) {|n,(r,c)|
(n[0]=='R' ? r : c) << n[1..-1].to_i}
Here's what's happening. Suppose:
s = "R1C4R2C5R32R4C7R18C6C12"
Then
a = s.scan(/[RC]\d+/)
#=> ["R1", "C4", "R2", "C5", "R32", "R4", "C7", "R18", "C6", "C12"]
scan uses the regex /([RC]\d+)/ to extract substrings that begin with 'R' or 'C' followed by one or more digits up to the next letter or end of the string.
b = a.each_with_object([[],[]]) {|n,(r,c)|(n[0]=='R' ? r : c) << n[1..-1].to_i}
#=> [[1, 2, 32, 4, 18], [4, 5, 7, 6, 12]]
The row values are given by [1, 2, 32, 4, 18]; the column values by [4, 5, 7, 6, 12].
Enumerable#each_with_object (v1.9+) creates an array comprised of two empty arrays, [[],[]]. The first subarray will contain the row values, the second, the column values. These two subarrays are represented by the block variables r and c, respectively.
The first element of a is "R1". This is represented in the block by the variable n. Since
"R1"[0] #=> "R"
"R1"[1..-1] #=> "1"
we execute
r << "1".to_i #=> [1]
so now
[r,c] #=> [[1],[]]
The next element of a is "C4", so we will execute:
c << "4".to_i #=> [4]
so now
[r,c] #=> [[1],[4]]
and so on.
rows, cols = "R1C4R2C5".scan(/R(\d+)C(\d+)/).flatten.partition.with_index {|_, index| index.even? }
> rows
=> ["1", "2"]
> cols
=> ["4", "5"]
Or
rows = "R1C4R2C5".scan(/R(\d+)/).flatten
=> ["1", "2"]
cols = "R1C4R2C5".scan(/C(\d+)/).flatten
=> ["4", "5"]
And to fix your code use:
word2.each {|a| col.push(a.delete('C')) if a.include? 'C' }
word2.each {|a| row.push(a.delete('R')) if a.include? 'R' }
I want to modify part of a string I have using Ruby.
The string is [x, y] where y is an integer that I want to change to its alphabetical letter. So say [1, 1] would become [1, A] and [1, 26] would become [1, Z].
Would a regular expression help me do this? or is there an easier way? I am not to strong with regular expressions, I am reading up on those now.
The shortest way I can think of is the following
string = "[1,1]"
array = string.chop.reverse.chop.reverse.split(',')
new_string="[#{array.first},#{(array.last.to_i+64).chr}]"
Maybe this helps:
Because we do not have an alphabet yet we can look up the position, create one.
This is a range converted to an array so you don't need to specify it yourself.
alphabet = ("A".."Z").to_a
Then we try to get the integer/position out of the string:
string_to_match = "[1,5]"
/(\d+)\]$/.match(string_to_match)
Maybe the regexp can be improved, however for this example it is working.
The first reference in the MatchData is holding the second integer in your "string_to_match".
Or you can get it via "$1".
Do not forget to convert it to an integer.
position_in_alphabet = $1.to_i
Also we need to remember that the index of arrays starts at 0 and not 1
position_in_alphabet -= 1
Finally, we can take a look which char we really get
char = alphabet[position_in_alphabet]
Example:
alphabet = ("A".."Z").to_a #=> ["A", "B", "C", ..*snip*.. "Y", "Z"]
string_to_match = "[1,5]" #=> "[1,5]"
/(\d+)\]$/.match(string_to_match) #=> #<MatchData "5]" 1:"5">
position_in_alphabet = $1.to_i #=> 5
position_in_alphabet -= 1 #=> 4
char = alphabet[position_in_alphabet] #=> "E"
Greetings~