1

我正在遍历单词列表,并在每个单词的开头插入字母表中的每个字母,代码如下:

def add_charac_front
  ("a".."z").each do |letter|
    @array.each do |list_word|
      list_word.insert(0, letter)
      puts list_word
    end #ends @array loop
  end #ends alphabet loop
end #ends method 

但是.insert正在发生变化@array,因此当我遍历@array字母“ ”时b,第一个不是“ ”而是“ ”。list_word@arrayHelloaHello

我需要完全相同的行为,但是对于@array我运行的每个字母循环来说都是相同的数组。当我执行此代码时,它工作正常:

def add_charac_front
  ("a".."z").each do |letter|
    @array.each do |list_word|
      puts "#{letter}#{list_word}"
    end #ends @array loop
  end #ends alphabet loop
end #ends method

但我最终想在 的不同部分插入字母list_word,而不仅仅是前面。

我想我可以做到这一点的另一种方法是.split("")list_word然后.insert(0, letter),然后.join。但这似乎更麻烦。

我该怎么做呢?

4

4 回答 4

2

Ruby 通过引用而不是值传递。这意味着list_word里面其实是指向里面的原话@array

如果您只想在list_word不影响原始数组的情况下使用它,则需要对其进行一次性复制,例如:

def add_charac_front
  ("a".."z").each do |letter|
    @array.each do |orig_word|
      list_word = orig_word.dup # duplicates the list_word
      list_word.insert(0, letter)
      puts list_word
    end #ends @array loop
  end #ends alphabet loop
end #ends method 
于 2012-09-14T05:44:29.327 回答
1

您还可以轻松地使用双引号创建一个新字符串并使用 #{varname} 这将创建一个新字符串。

irb> @array = %w(foo bar baz)
=> ["foo", "bar", "baz"]
irb> ("a".."e").inject([]) { |m,c| 
                m.concat(@array.map { |item| "#{c}-#{item}" });
                m }
=> ["a-foo", "a-bar", "a-baz", "b-foo", "b-bar", "b-baz", "c-foo", "c-bar", "c-baz", "d-foo", "d-bar", "d-baz", "e-foo", "e-bar", "e-baz"]

使用 map 创建新数组不太容易出错,然后当您需要将另一个数组折叠到其中时使用注入。如果您对使用 inject 感到不舒服,可以使用 map 和 flatten 来实现相同的结果:

irb> ("a".."e").map { |c| @array.map { |item| "#{c}-#{item}" } }
=> [["a-foo", "a-bar", "a-baz"], ["b-foo", "b-bar", "b-baz"], ["c-foo", "c-bar", "c-baz"],     ["d-foo", "d-bar", "d-baz"], ["e-foo", "e-bar", "e-baz"]]
irb> ("a".."e").map { |c| @array.map { |item| "#{c}-#{item}" } }.flatten
=> ["a-foo", "a-bar", "a-baz", "b-foo", "b-bar", "b-baz", "c-foo", "c-bar", "c-baz", "d-foo", "d-bar", "d-baz", "e-foo", "e-bar", "e-baz"]

在 Enumerables 上使用链式操作可以轻松检查每个执行点的状态。然后当你需要打印出来时,你可以附加 .each { |x| 放 x }

如果您经常这样做,为什么不安装 gem cartesian,这使得获取两个数组的笛卡尔积变得非常简单,这正是您所需要的:

irb> require 'cartesian'
=> true
irb> Cartesian::product(("a".."c"), %w(foo bar baz))
=> [["a", "foo"], ["a", "bar"], ["a", "baz"], ["b", "foo"], ["b", "bar"], ["b", "baz"], ["c",   "foo"], ["c", "bar"], ["c", "baz"]]
irb> Cartesian::product(("a".."c"), %w(foo bar baz)).map { |x| "#{x.first}-#{x.last}" }
=> ["a-foo", "a-bar", "a-baz", "b-foo", "b-bar", "b-baz", "c-foo", "c-bar", "c-baz"]
于 2012-09-14T07:45:07.560 回答
0

如果你觉得你需要使用插入,那么你可以创建一个新的字符串副本。

def add_charac_front
  ("a".."z").each do |letter|
     @array.each do |list_word|
       t = String.new(list_word).insert(0,letter)
       puts t
     end #ends @array loop
  end #ends alphabet loop
end #ends method 
于 2012-09-14T05:31:53.850 回答
0

不确定我是否遵循要求,但我建议只操作数组本身

# example.rb

@alpha = %w{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}

def add_charac_front(array)
  return @alpha + array
end

或者上面的代码实际上是将字母插入到彼此的前面,所以它相当于反转 alpha 数组并将其插入到前面

@reverse_alpha = alpha.reverse

def add_charac_front(array)
  return @reverse_alpha + array
end

希望这可以帮助。您还可以使用这样的范围来连接子数组

a2 = %w{b c}
a3 = @alpha[0..4] + a2 + @alpha[5..13]
于 2012-09-14T05:44:30.353 回答