如何记住另一个数组中的交换数组元素?

时间:2013-09-01 11:09:35

标签: ruby arrays permutation swap

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

当我在循环中打印出来时,它会正确显示所有排列。但是当我打印出烫发(我用它来存储a的所有不同排列)时,它只显示重复几次的1个版本。我该如何解决这个问题?

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

3 个答案:

答案 0 :(得分: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之间的一个区别与“freeze”方法有关。如果我调用了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>

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

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

答案 1 :(得分: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

...

答案 2 :(得分:0)

如果您不喜欢重新发明轮子,可以使用facet 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]]