how to get remain of `delete_at` without destruction - ruby

I want to delete a value from an Array and get remain of it like this:
a = [1, 2, 3, 4]
=> [1, 2, 3, 4]
a.delete_at(2)
=> 3
a
=> [1, 2, 4]
How can I get [1, 2, 4] without destruction of the variable?

There are a couple of ways you can do, admittedly, they don't seem very elegant:
a[0..1] + a[3..-1]
# => [1, 2, 4]
a.dup.tap { |x| x.delete_at(2) }
# => [1, 2, 4]
a.values_at(0..1, 3..-1)
# => [1, 2, 4]
Personally, I think the way which conveys your intention best is:
a.reject.with_index { |_, i| i == 2 }
# => [1, 2, 4]

Related

Why a new call of a method with exclamation mark affects all previous calls of that method?

I'm sorry if this is a duplicate - I couldn't find anything similar in the existing posts.
I understand the difference between methods like shuffle and shuffle!. However, I am confused why calling the method more than once would result in changing the variables of all objects that previously referred to it? I'd expect once we apply a method, that the variable gets a value and we're done with it. Not that it continues to refer to the method call and the argument passed and that it would get re-evaluated later on.
I thought it's best to demonstrate with an example:
irb(main):001:1* def shuffle(arr)
irb(main):002:1* arr.shuffle!
irb(main):003:0> end
=> :shuffle
irb(main):004:0> arr = [1,2,3,4]
=> [1, 2, 3, 4]
irb(main):005:0> one = shuffle(arr)
=> [4, 2, 3, 1]
irb(main):006:0> two = shuffle(arr)
=> [1, 2, 4, 3]
irb(main):007:0> one
=> [1, 2, 4, 3]
So, here I'd expect one to stay [4, 2, 3, 1]. However, with each new call, all previous ones would get equated to the latest result of the method call. I realise it should have something to do with calling it with the same argument arr, but still doesn't quite make sense.
Array#shuffle! shuffles the array in-place and returns its receiver:
ary = [1, 2, 3, 4]
ary.equal?(ary.shuffle!) #=> true
Assigning the result from shuffle! to another variable doesn't change this. It merely results in two variables referring to the same array:
a = [1, 2, 3, 4]
b = a.shuffle!
a #=> [2, 4, 1, 3]
b #=> [2, 4, 1, 3]
a.equal?(b) #=> true
You probably want a new array. That's what Array#shuffle (without !) is for:
a = [1, 2, 3, 4]
b = a.shuffle
a #=> [1, 2, 3, 4]
b #=> [2, 4, 1, 3]
Even if shuffle returns the element in the original order, you'll get another array instance:
a = [1, 2, 3, 4]
b = a.shuffle until b == a
a #=> [1, 2, 3, 4]
b #=> [1, 2, 3, 4]
a.equal?(b) #=> false

Duplicate elements of array in ruby

I find a lot of reference about removing duplicates in ruby but I cannot find how to create duplicate.
If I have an array like [1,2,3] how can I map it to an array with dubbed items? [1,1,2,2,3,3]
Is there a method?
Try this one
[1, 2, 3].flat_map { |i| [i, i] }
=> [1, 1, 2, 2, 3, 3]
Here's yet another way, creating the array directly with Array#new :
array = [1, 2, 3]
repetitions = 2
p Array.new(array.size * repetitions) { |i| array[i / repetitions] }
# [1, 1, 2, 2, 3, 3]
According to fruity, #ursus's answer, #ilya's first two answers and mine have comparable performance. transpose.flatten is slower than any of the others.
#Ursus answer is the most clean, there are possible solutions:
a = [1, 2, 3]
a.zip(a).flatten
#=> [1, 1, 2, 2, 3, 3]
Or
a.inject([]) {|a, e| a << e << e} # a.inject([]) {|a, e| n.times {a << e}; a}
=> [1, 1, 2, 2, 3, 3]
Or
[a, a].transpose.flatten # ([a] * n).transpose.flatten
=> [1, 1, 2, 2, 3, 3]
Try this:
[1, 2, 3] * 2
=> [1, 2, 3, 1, 2, 3]
You might want it sorted:
([1, 2, 3] * 2).sort
=> [1, 1, 2, 2, 3, 3]

How can I get the next n number of elements using a Ruby enumerator?

I am trying to get the next n number of elements using a Ruby enumerator, with this:
a = [1, 2, 3, 4, 5, 6]
enum = a.each
enum.next(2) # expecting [1, 2]
enum.next(2) # expecting [3, 4]
But #next does not support that. Is there another way that I can do that?
Or shall I do?
What is the correct Ruby way to do that?
You can use take method
enum.take(2)
If you need slices of two elements, you could do:
e = enum.each_slice(2)
p e.next
#=> [1, 2]
p e.next
#=> [3, 4]
a = [1, 2, 3, 4, 5, 6]
enum = a.dup
enum.shift(2) # => [1, 2]
enum.shift(2) # => [3, 4]

Oneliner association from array in Ruby

In Coffeescript I can do this:
[one..., two] = [1, 2, 3, 4, 5]
# one = [1, 2, 3, 4]
# two = 5
Is there any way to do this (oneliner) in Ruby?
EDIT
I know that I can do this:
one = [1, 2, 3, 4, 5]
two = one.slice!(-1)
EDIT 2
Oneliner could look like this:
two = (one = [1, 2, 3, 4, 5]).slice!(-1)
but this seems too ugly for me.
This should do it:
*one, two = [1, 2, 3, 4, 5]
one
# => [1, 2, 3, 4]
two
# => 5
You can see some more explanations on splat and array destructuring here
irb(main):001:0> a = [1,2,3,4,5]
=> [1, 2, 3, 4, 5]
irb(main):002:0> *one, two = a
=> [1, 2, 3, 4, 5]
irb(main):003:0> one
=> [1, 2, 3, 4]
irb(main):004:0> two
=> 5

How to make an array containing a duplicate of an array

I couldn't find a way to build an array such as
[ [1,2,3] , [1,2,3] , [1,2,3] , [1,2,3] , [1,2,3] ]
given [1,2,3] and the number 5. I guess there are some kind of operators on arrays, such as product of mult, but none in the doc does it. Please tell me. I missed something very simple.
Array.new(5, [1, 2, 3]) or Array.new(5) { [1, 2, 3] }
Array.new(size, default_object) creates an array with an initial size, filled with the default object you specify. Keep in mind that if you mutate any of the nested arrays, you'll mutate all of them, since each element is a reference to the same object.
array = Array.new(5, [1, 2, 3])
array.first << 4
array # => [[1, 2, 3, 4], [1, 2, 3, 4], [1, 2, 3, 4], [1, 2, 3, 4], [1, 2, 3, 4]]
Array.new(size) { default_object } lets you create an array with separate objects.
array = Array.new(5) { [1, 2, 3] }
array.first << 4
array #=> [[1, 2, 3, 4], [1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2, 3]]
Look up at the very top of the page you linked to, under the section entitled "Creating Arrays" for some more ways to create arrays.
Why not just use:
[[1, 2, 3]] * 5
# => [[1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2, 3]]
The documentation for Array.* says:
...returns a new array built by concatenating the int copies of self.
Typically we'd want to create a repeating single-level array:
[1, 2, 3] * 2
# => [1, 2, 3, 1, 2, 3]
but there's nothing to say we can't use a sub-array like I did above.
It looks like mutating one of the subarrays mutates all of them, but that may be what someone wants.
It's like Array.new(5, [1,2,3]):
foo = [[1, 2, 3]] * 2
foo[0][0] = 4
foo # => [[4, 2, 3], [4, 2, 3]]
foo = Array.new(2, [1,2,3])
foo[0][0] = 4
foo # => [[4, 2, 3], [4, 2, 3]]
A work-around, if that's not the behavior wanted is:
foo = ([[1, 2, 3]] * 2).map { |a| [*a] }
foo[0][0] = 4
foo # => [[4, 2, 3], [1, 2, 3]]
But, at that point it's not as convenient, so I'd use the default Array.new(n) {…} behavior.

Resources