I am monkey patching the Array
class to add an Array#sample!
method:
Array#sample!
should be a destructive version ofArray#sample
that removes the returned elements from the array.Array#sample!
should take the same arguments asArray#sample
.
However, I fail at passing the arguments correctly. Here is what I am trying:
class Array
def sample!(n = nil, **args)
if n
self.sample(n, args).map { |e| self.delete(e) }
else
self.delete(self.sample(args))
end
end
end
a = (1..10).to_a
p a.sample
p a.sample(4)
p a.sample(random: Random.new(1))
p a.sample(4, random: Random.new(1))
p a.sample!
p a.sample!(4)
p a.sample!(random: Random.new(1))
p a.sample!(4, random: Random.new(1))
And it fails with an no implicit conversion of Hash into Integer
message :o(
CodePudding user response:
Let's start with the argument passing. You can either do it like this: (the splat (*
) effectively omits the positional argument if n
is nil
)
class Array
def my_sample(n = nil, **kwargs)
sample(*n, **kwargs)
end
end
[1, 2, 3].my_sample #=> 3
[1, 2, 3].my_sample(2) #=> [1, 3]
[1, 2, 3].my_sample(random: Random.new(1)) #=> 2
[1, 2, 3].my_sample(2, random: Random.new(1)) #=> [2, 3]
Or you could use a conditional:
class Array
def my_sample(n = nil, **kwargs)
if n
sample(n, **kwargs)
else
sample(**kwargs)
end
end
end
Implementing a sample!
method that works just like sample
but which also removes those element(s) might be a little more complex than your approach.
Since arrays can contain the same element multiple times, you have to take special care to remove the correct ones. (you cant just remove all duplicates, neither an arbitrary one)
Something like this would probably work:
class Array
def sample!(n = nil, **kwargs)
indices = (0...size).to_a
if n
samples = indices.sample(n, **kwargs)
remaining = indices - samples
return_value = values_at(*samples)
else
sample = indices.sample(**kwargs)
remaining = indices - [sample]
return_value = at(sample)
end
replace(values_at(*remaining))
return_value
end
end
Here, I'm creating an array of indices (which are guaranteed to be unique) and sample from that array. I then determine the remaining indices (which is simply the difference), set the return value and adjust the array content.
You could unify both code paths but that makes the code a little harder to read.