如何从一个输入创建两个单独的数组?

时间:2014-02-16 03:30:47

标签: ruby arrays

描述:

我的代码的目的是接受一系列R和C的输入,并简单地将字符后面的每个数字存储在其正确的数组中。

例如:“输入格式如下:R1C4R2C5

列数组:[4,5]行数组:[1,2]

我的问题是我得到这样的输出:

[" ", 1]
[" ", 4]
[" ", 2]
[" ", 5]

**如何在一个数组中获取R之后的所有Row整数,以及在另一个单独数组中使用C之后的所有Column整数。我不想创建多个数组,而只是两个。

帮助!

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

3 个答案:

答案 0 :(得分:2)

x = "R1C4R2C5"
col = []
row = []
x.chars.each_slice(2) { |u|  u[0] == "R" ? row << u[1] : col << u[1] }
p col
p row

答案 1 :(得分:1)

代码的主要问题是您复制行和列的操作。你想写“干”代码,代表“不要重复自己”。

从您的代码作为模型开始,您可以通过编写这样的方法来干掉它,从输入字符串中提取所需的信息,并为行调用一次,为列调用一次:

def doit(s, c)
...
end

此处s是输入字符串,c是字符串“R”或“C”。在你想要的方法内 提取以c的值开头并且后跟数字的子字符串。您使用String#scan的决定很好,但您需要一个不同的正则表达式:

def doit(s, c)
  s.scan(/#{c}\d+/)
end

我会解释正则表达式,但让我们先试试这个方法。假设字符串是:

s = "R1C4R2C5"

然后

rows = doit(s, "R") #=> ["R1", "R2"]
cols = doit(s, "C") #=> ["C4", "C5"]

这不是你想要的,但很容易修复。首先,正则表达式。正则表达式首先查找字符#{c}#{c}将变量c的值转换为文字字符,在本例中为“R”或“C”。 \d+表示字符#{c}必须后跟一个或多个数字0-9,与下一个非数字(此处为“R”或“C”)之前的数字一样多字符串的结尾。

现在让我们修复方法:

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]

成功!与以前一样,a => ["R1", "R2"]如果c => "R"a =>["C4", "C5"] c => "C"a.map {|str| str[1..-1]}a的每个元素映射到一个由所有字符组成的字符串,但第一个字符(例如"R12"[1..-1] => "12"),我们有b => ["1", "2"]b =>["4", "5"]。然后我们再次应用map将这些字符串转换为其Fixnum等价物。表达式b.map(&:to_i)

的简写
b.map {|str| str.to_i}

方法返回最后计算的数量,因此,如果它是您想要的,就像在这里一样,最后不需要return语句。

然而,这可以通过几种方式简化。首先,我们可以通过删除最后一个语句并将上面的一个更改为:

来组合最后两个语句
a.map {|str| str[1..-1].to_i}

也摆脱了局部变量b。第二个改进是“链接”剩余的两个陈述,这也使我们摆脱了另一个临时变量:

def doit(s, c)
  s.scan(/#{c}\d+/).map { |str| str[1..-1].to_i }
end

这是典型的Ruby代码。

请注意,通过这种方式,字符串中的行和列引用不需要交替,并且数值可以具有任意数字的数字。

这是另一种做同样事情的方法,有些人可能会认为更像Ruby:

s.scan(/[RC]\d+/).each_with_object([[],[]]) {|n,(r,c)|
  (n[0]=='R' ? r : c) << n[1..-1].to_i}

这是发生了什么。假设:

s = "R1C4R2C5R32R4C7R18C6C12"

然后

a = s.scan(/[RC]\d+/)
  #=> ["R1", "C4", "R2", "C5", "R32", "R4", "C7", "R18", "C6", "C12"]

scan使用正则表达式/([RC]\d+)/提取以“R”或“C”开头的子字符串,后跟一个或多个数字,直到字符串的下一个字母或结尾。

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]]

行值由[1, 2, 32, 4, 18]给出;列值按[4, 5, 7, 6, 12]

Enumerable#each_with_object(v1.9 +)创建一个由两个空数组[[],[]]组成的数组。第一个子数组将包含行值,第二个子数组包含列值。这两个子数组分别由块变量rc表示。

a的第一个元素是“R1”。这由变量n在块中表示。由于

"R1"[0]       #=> "R"
"R1"[1..-1]   #=> "1"

我们执行

r << "1".to_i #=> [1]

所以现在

[r,c]         #=> [[1],[]]

a的下一个元素是“C4”,因此我们将执行:

c << "4".to_i #=> [4]

所以现在

[r,c]         #=> [[1],[4]]

等等。

答案 2 :(得分:1)

rows, cols = "R1C4R2C5".scan(/R(\d+)C(\d+)/).flatten.partition.with_index {|_, index| index.even?  }
> rows
=> ["1", "2"] 
> cols
=> ["4", "5"] 

或者

rows = "R1C4R2C5".scan(/R(\d+)/).flatten
=> ["1", "2"] 
cols = "R1C4R2C5".scan(/C(\d+)/).flatten
=> ["4", "5"] 

要修复您的代码使用:

word2.each {|a| col.push(a.delete('C')) if a.include? 'C' }
word2.each {|a| row.push(a.delete('R')) if a.include? 'R' }