Ruby Map Method编辑原始数组吗?

fr_*_*awd 2 ruby dictionary reference enumerate

def removal(arr)
    letters ="i"
    p arr  
    new_array = arr.map do |c_word|
        c_word.each_char.with_index do |char, index|
            if letters.include?(char)
                c_word[index] = "*"
            end    
        end
    end     
    p arr #the original array is getting edited? why?
    p new_array     

end

removal(["hiiiiiigh","git", "training"])
Run Code Online (Sandbox Code Playgroud)

在这段代码中,map方法中的原始数组(arr)不断得到编辑。我以为地图不会编辑原始数组。如果需要编辑原始文件,则可以使用.map!

我相信这与嵌套枚举器或我没有看到的变量引用有关。我使用了while循环,而不是each_char.with_index,并且map仍然可以编辑原始数组。为什么要编辑原始数组?

Jör*_*tag 6

实际上,您至少在以下两个地方错了:

  • map编辑原始阵列
  • 实际上,原始阵列未被编辑在所有

如果仔细观察,该数组没有更改,只有该数组中的字符串已更改。它是不是map正在这样做,这是String#[]=,你在呼唤这里:

c_word[index] = "*"
Run Code Online (Sandbox Code Playgroud)

因此,您正在调用一种用于编辑字符串的方法,因此对字符串进行编辑不会感到惊讶!


TeW*_*eWu 5

考虑使用:

  • map“我想基于现有数据创建新数据”
  • each“我要么不想更改任何数据,要么更改现有数据”

考虑到这一点,您正在做的事情是map与数组一起使用,以基于现有数组创建新数组,然后each用于修改现有字符串中的字符。这就是为什么原始数组中的字符串最终会被修改的原因。

若要修复此问题map,请先“基于现有数组创建新数组”,然后第二次“基于现有字符串创建新字符串”。这样,原始字符串将不会被修改。

def removal(arr)
  letters ="i"
  p arr
  new_array = arr.map do |word|
    word.chars.map do |char|
      letters.include?(char) ? '*' : char
    end.join
  end
  p arr
  p new_array
end

removal(["hiiiiiigh","git", "training"])  #=> ["hiiiiiigh", "git", "training"]
                                          #   ["hiiiiiigh", "git", "training"]
                                          #   ["h******gh", "g*t", "tra*n*ng"]
Run Code Online (Sandbox Code Playgroud)

这个问题的更实际的解决方案将是这样的:

def censor(strings, forbidden_chars_string, censor_char = '*')
  re = Regexp.union(forbidden_chars_string.chars)
  strings.map {|str| str.gsub(re, censor_char) }
end

p ["hiiiiiigh","git", "training"]                     #=> ["hiiiiiigh", "git", "training"]
p censor(["hiiiiiigh","git", "training"], "i")        #=> ["h******gh", "g*t", "tra*n*ng"]
p censor(["hiiiiiigh","git", "training"], "gn", '_')  #=> ["hiiiiii_h", "_it", "trai_i__"]
Run Code Online (Sandbox Code Playgroud)