0

这真让我抓狂!我一直在尝试编写一个 Ruby 方法来查找所有排列,以解决 Project Euler 的问题 24。当我交换数组的元素时,它们会正确交换。但是当我尝试将这个交换数组存储在一个不同的数组中时,这个新数组只记得我交换数组的最新副本!它不会记住旧版本。

当我在循环期间打印出 a 时,它会正确显示所有排列。但是当我打印出 perm (我用它来存储 a 的所有不同排列)时,它只显示一个重复多次的版本。我该如何解决?

a = [0, 1, 2, 3]
perms = []

p "a = #{a}"              # output: "a = [0, 1, 2, 3]"
perms << a                # add a to perms array
p "perms = #{perms}"      # output: "perms = [[0, 1, 2, 3]]"

a[0], a[1] = a[1], a[0]   # swap 1st 2 elements of a
p "a = #{a}"              # output: "a = [1, 0, 2, 3]"
perms << a                # add a to perms array
p "perms = #{perms}"      # "perms = [[1, 0, 2, 3], [1, 0, 2, 3]]"

a[1], a[2] = a[2], a[1]   # swap 2nd 2 elements of a
p "a = #{a}"              # "a = [1, 2, 0, 3]"
perms << a                # add a to perms array
p "perms = #{perms}"      # "perms = [[1, 2, 0, 3], [1, 2, 0, 3], [1, 2, 0, 3]]"

感谢下面的 Sawa,“dup”和“clone”方法都解决了我的问题!为什么我原来的方法不起作用?我什么时候会使用“dup”与“clone”?请给我一些代码示例。

a[0], a[1] = a[1], a[0]   # swap 1st 2 elements of a
p "a = #{a}"              # output: "a = [1, 0, 2, 3]"
b = a.dup (or a.clone)
perms << b
p "perms = #{perms}"      # "perms = [[0, 1, 2, 3], [1, 0, 2, 3]]" *** it remembers!
a[1], a[2] = a[2], a[1]   # swap 2nd 2 elements of a
p "a = #{a}"              # "a = [1, 2, 0, 3]"
b = a.dup (or a.clone)
perms << b
p "perms = #{perms}"      # "perms = [[0, 1, 2, 3], [1, 0, 2, 3], [1, 2, 0, 3]]" 
4

3 回答 3

2

Ruby 中的变量(有一些例外,例如绑定到整数的变量)包含对对象的引用,而不是值。这是运行“irb”的示例:

1.9.3p374 :021 > str1="hi"
 => "hi" 
1.9.3p374 :022 > str2=str1
 => "hi" 
1.9.3p374 :023 > str1.replace("world")
 => "world" 
1.9.3p374 :024 > str2
 => "world" 

您会注意到,一旦我替换了 str1 的值,str2 的“值”也会发生变化。那是因为它包含对 str1 对象的引用。我知道 dup 和 clone 之间的一个区别与“冻结”方法有关。如果我调用了 str1.freeze,那么它将阻止对象 str1 引用被修改,例如,

1.9.3p374 :055 > str1.freeze
 => "hi" 
1.9.3p374 :056 > str1[0]="b"
RuntimeError: can't modify frozen String
    from (irb):56:in `[]='
    from (irb):56
    from /.rvm/rubies/ruby-1.9.3-p374/bin/irb:13:in `<main>

“复制” - 冻结对象不会创建冻结对象,而克隆会。

编辑:只是轻微的更新......当将右侧的对象分配给左侧的变量(例如,str = Object.new)时,该变量接收对象引用。将一个变量分配给另一个变量时,左侧变量会收到右侧变量包含的引用的副本。无论哪种情况,您仍然将对象引用存储在左侧变量中。

于 2013-09-01T23:07:24.723 回答
1

您的原始文件不起作用,因为您一直在修改相同的数组实例a

dup每次将原始数组修改为不同的数组之前,都取一个。或者,Array通过不依赖破坏性方法创建一个新的实例。

a = original_array

b = a.dup
... # do some modifications to `b`
perms << b

c = a.dup
... # do some modifications to `c`
perms << c

...
于 2013-09-01T11:11:06.393 回答
0

如果您不喜欢重新发明轮子,可以使用 facets gem。

gem install facets

https://github.com/rubyworks/facets/blob/d96ec0d700d1d7180ccbb5452e0a926386ec0b32/lib/backport/facets/array/permutation.rb

require 'facets'

[1, 2, 3].permutation
#=> [[1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1]]
于 2013-09-01T11:43:49.503 回答