在原数组中修改 - Ruby

3

我想知道为什么以下代码无法直接修改数组。

我的代码如下:

@card.map!.with_index {|value, key|  key.even? ? value*=2 : value}

这段代码遍历一个数组,对于所有偶数下标的元素进行值的翻倍操作。

接着我执行了以下操作:

@card.join.split('').map!{|x| x.to_i}

将数组连接成一个巨大的数字,将它们分割为单个数字,然后将它们映射回整数数组。从步骤一到步骤二唯一的真正变化是步骤一看起来像a=[1,2,12],而步骤二看起来像a=[1,2,1,2]。对于第二步,即使我在p @card时使用.map!,在第一步之后它看起来完全相同。如果我想继续使用新数组,我必须将第二步设置为某些内容。为什么会这样?第二步中的.map!是否不会直接修改数组?或者我的方法链接是否抵消了我的能力? 致敬。


你第一个代码块中的表达式 value*=2 是误导性的,你应该改为写成 value * 2 - David Grayson
2个回答

2
简而言之,只有当方法链中的每个方法都是修改对象的方法时,该方法链才会直接在原始对象上进行修改。
在这种情况下,最重要的区别在于您在对象上调用的第一个方法。您的第一个示例调用了map!,这是一种直接修改数组的方法。with_index在此示例中并不重要,它只是改变了map!的行为。
您的第二个示例在数组上调用了joinjoin不会直接在原始数组上进行修改,而是返回一个完全不同的对象:字符串。然后您对字符串进行了split,创建了一个新的数组,并且随后的map!直接在新数组上进行修改。
因此,在第二个示例中,您需要再次将结果赋值给变量:
@card = @card.join.split('').map{ |x| x.to_i }

可能有其他计算所需结果的方法。但由于您未提供输入和输出示例,因此不清楚您要实现什么目标。


2

第二步中的.map!不是原地修改数组吗?

是的,它确实会修改数组,但它修改的数组不是@card。 split()方法返回一个新数组,即不是@card的数组,而map!会原地修改这个新数组。

看看这个例子:

tap{|x|...} → x
Yields [the receiver] to the block, and then returns [the receiver]. 
The primary purpose of this method is to “tap into” a method chain, 
in order to perform operations on intermediate results within the chain.  

@card = ['a', 'b', 'c']
puts @card.object_id

@card.join.split('').tap{|arr| puts arr.object_id}.map{ |x| x.to_i }  #arr is whatever split() returns

--output:--
2156361580
2156361380

在 Ruby 程序中,每个对象都有一个唯一的 object_id。


@HectorOfTroy407,点击spickermann答案左侧的勾选框。您也可以通过点击0上方的向上箭头来点赞spickermann的答案。 - 7stud

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接