使用Ruby非破坏性地将对象附加到数组

时间:2014-10-11 20:32:02

标签: ruby arrays

所以我需要为Array创建一个实例方法,它接受两个参数,一个数组的大小和一个将附加到数组的可选对象。

如果size参数小于或等于Array.length或size参数等于0,则只返回数组。如果可选参数留空,则输入nil。

示例输出:

array = [1,2,3]

array.class_meth(0) => [1,2,3]
array.class_meth(2) => [1,2,3]
array.class_meth(5) => [1,2,3,nil,nil]
array.class_meth(5, "string") => [1,2,3,"string","string"]

以下是我一直在处理的代码:

class Array
  def class_meth(a ,b=nil)
    self_copy = self
    diff = a - self_copy.length
    if diff <= 0
      self_copy
    elsif diff > 0
      a.times {self_copy.push b}
    end
    self_copy
  end

  def class_meth!(a ,b=nil)
    # self_copy = self
    diff = a - self.length
    if diff <= 0
      self
    elsif diff > 0
      a.times {self.push b}
    end
    self
  end
end

我已经能够创建破坏性方法class_meth!,但似乎无法找到使其具有非破坏性的方法。

3 个答案:

答案 0 :(得分:1)

这里(恕我直言)是一个更清洁的解决方案:

class Array
  def class_meth(a, b = nil)
    clone.fill(b, size, a - size)
  end

  def class_meth!(a, b = nil)
    fill(b, size, a - size)
  end
end

我认为它应该满足您的所有需求。为了避免代码重复,你可以让任何一种方法调用另一种方法(当然,不能同时调用两种方法):

def class_meth(a, b = nil)
  clone.class_meth!(a, b)
end

或:

def class_meth!(a, b = nil)
  replace(class_meth(a, b))
end

答案 1 :(得分:0)

self_copy = self 制作新对象 - assignment in Ruby never "copies" or creates a new object implicitly

因此,非破坏性案例适用于相同的对象(调用该方法的实例),就像在破坏性案例中一样,不同的变量绑定到同一个对象 - 即{{ 3}}是真的。

最简单的解决方案是仅使用self.equal? self_copy

def class_meth(a ,b=nil)
  self_copy = self.clone   # NOW we have a new object ..
  # .. so we can modify the duplicate object (self_copy)
  # down here without affecting the original (self) object.
end

如果#clone无法使用,则其他解决方案涉及#clone, keeping in mind it is a shallow clone operation或获取数组create a new array(返回新数组)或甚至追加(返回新数组)#slice ;但是,与#clone不同,它们通常会锁定返回一个数组而不是任何可能派生的子类型。

在进行上述更改后,还应该明白它可以这样写:

def class_meth(a ,b=nil)
  clone.class_meth!(a, b)  # create a NEW object; modify it; return it
                           # (assumes class_meth! returns the object)
end

使用其中一种形式来避免修改当前实例的#class_meth!#class_meth的更合适的实现仍然是一个练习。


FWIW:那些是实例方法,这是合适的,而不是&#34; class meth [ods]&#34 ;;不要被错误的命名所迷惑。

答案 2 :(得分:0)

当你的问题被诊断出来时,我会就你如何做到这一点提出一个建议。我假设你想要传递两个,可选择三个,而不是一个,也可以选择两个参数。

<强>代码

class Array
  def self.class_meth(n, arr, str=nil)
    arr + (str ? ([str] : [nil]) * [n-arr.size,0].max)
  end
end

<强>实施例

Array.class_meth(0, [1,2,3])
  #=> [1,2,3]
Array.class_meth(2, [1,2,3])
  #=> [1,2,3]
Array.class_meth(5, [1,2,3])
  #=> [1,2,3,nil,nil]
Array.class_meth(5, [1,2,3], "string")
  #=> [1,2,3,"string","string"]
Array.class_meth(5, ["dog","cat","pig"])
  #=> [1,2,3,"string","string"]
Array.class_meth(5, ["dog","cat","pig"], "string")
  #=> [1,2,3,"string","string"]
Array.class_meth(5, ["dog","cat","pig"])
  #=> ["dog", "cat", "pig", nil, nil]
Array.class_meth(5, ["dog","cat","pig"], "string")
  #=> ["dog", "cat", "pig", "string", "string"]

在撤回答案之前,@ PatriceGahide建议使用Array#fill。那将是一个改进;即,用以下内容替换操作线:

arr.fill(str ? str : nil, arr.size, [n-arr.size,0].max)