Method for padding an array in Ruby
It is killed, because you are entering infinite loop. until a[b-1]
will not finish, because when you add nils to the array, you will get:
a == [1, 2, 3, nil, nil, nil, nil, nil, nil, nil]
after few iterations and a[b-1] will be nil
, which is falsey. Until will never stop.
About the second question, it is easy to extend existing Array class:
class Array
def padding(i, value=nil)
(i - length).times { self << value }
self
end
end
Result as you expected:
[1,2,3].padding(10)
#=> [1, 2, 3, nil, nil, nil, nil, nil, nil, nil]
[1,2,3].padding(10, "YES")
#=> [1, 2, 3, "YES", "YES", "YES", "YES", "YES", "YES", "YES"]
Note the method about modifies existing array (so due to Ruby conventions should be called padding!
):
a = [1,2,3]
#=> [1, 2, 3]
a.padding(10, "YES")
#=> [1, 2, 3, "YES", "YES", "YES", "YES", "YES", "YES", "YES"]
a
#=> [1, 2, 3, "YES", "YES", "YES", "YES", "YES", "YES", "YES"]
But of course you can easy create the version of the method which doesn't modify. I assumed you want to modify the array, because your original method did it.
Pad an array to be a certain size
Edited due to my misunderstanding of the question. Pervious version of my answer padded from the right side, but the question was asking to do it from the left side. I corrected it accordingly. This is due to naming convention. ljust
, rjust
are builtin methods for String
, and I extended that convention to Array
, but that corresponds to padright
and padleft
, respectively, in the terminology of the question.
Destructive methods
def padleft!(a, n, x)
a.insert(0, *Array.new([0, n-a.length].max, x))
end
def padright!(a, n, x)
a.fill(x, a.length...n)
end
It would be more natural to have it defined on Array
class:
class Array
def rjust!(n, x); insert(0, *Array.new([0, n-length].max, x)) end
def ljust!(n, x); fill(x, length...n) end
end
Non-destructive methods
def padleft(a, n, x)
Array.new([0, n-a.length].max, x)+a
end
def padright(a, n, x)
a.dup.fill(x, a.length...n)
end
or
class Array
def rjust(n, x); Array.new([0, n-length].max, x)+self end
def ljust(n, x); dup.fill(x, length...n) end
end
Creating a Ruby method that pads an Array
In all 3 of your tries, you are returning the original array if desired_size is greater than the original array size. You have that backwards. In other words, you just return instead of padding.
Your first attempt was close. You need to:
1) Fix your conditional check.
2) It's OK to modify the self array, so the more complicated tries are not necessary.
3) Make sure you return self no matter what you do.
By modifying self, not only do you return the modified array, but you also change the array held by the variable test_array
. So if you were to do:
test_array = [1, 2, 3]
puts test_array.pad(5, 4).inspect // prints [1, 2, 3, 4, 4]
puts test_array // prints [1, 2, 3, 4, 4]
In Ruby, when a function modifies self, the function name ends with a !
, so if you were to write it modifying self, it would be better to name it pad!
.
If you want to write it so that it doesn't modify self, you could start with:
array = self.dup
and then do all of your operations on array
.
How to pad strings with zeros in Ruby
There is a zero-padding function for Strings in Ruby:
puts acct.rjust(23, '0')
ruby padding an array
Your non-destructive version is actually destructive. What you want is probably this:
def pad(array, min_size, value = nil)
pad!(array.clone, min_size, value)
end
There's no point in implementing the same behaviour twice. Make one bridge off of the other.
Padding a number with zeros
puts 1.to_s.rjust(3, "0")
#=> 001
puts 10.to_s.rjust(3, "0")
#=> 010
puts 100.to_s.rjust(3, "0")
#=> 100
The above code would convert your user.id into a string, then String.rjust() method would consider its length and prefix appropriate number of zeros.
Separate an array of arrays to be passed into a method as multiple objects
What I think you're attempting to do can be accomplished by using the splat operator at the time of method invocation, like such:
hello(*my_array)
Here's a complete example:
def foo(a, *b)
puts a.inspect
puts b.inspect
end
foo(*[[1, 2], [3, 4], [5, 6]])
Prints the following:
[1, 2]
[[3, 4], [5, 6]]
Edit: Other solution
Now that you've pasted the source my opinion is that the method should be re-written to take a single parameter instead of using the splat operator in the parameters to pull out the first
and rest
. The reason is that if the length of the multidimensional array changes at runtime you'd be better off pulling out first
and rest
inside the method so you're not having to use the splat everywhere.
def interleave(args)
a, *args = args
max_length = args.map(&:size).max
padding = [nil]*[max_length-a.size, 0].max
(a+padding).zip(*args).flatten.compact
end
foo([[1, 2], [3, 4], [5, 6]])
Ruby each_slice into sub arrays and set default element values if last sub-array is different size to other sub-arrays
#tap
into the resulting array and #fill
the last element with the necessary number of false
elements:
array = ["1", "b", "0", "7", "9", "2", "a", "a", "5", "7"]
array
.each_slice(3)
.to_a
.tap { |a| a.last.fill(false, a.last.length, 3 - a.last.length) }
Related Topics
How to Reset a Factory_Girl Sequence
How to Print Stdout Immediately
Automatically Open a File as Binary with Ruby
Str.Each in Ruby Isn't Working
How to Use "_Blank" or "_New" in Rails
How to Ignore a Folder in Zeitwerk for Rails 6
Ruby Pipes: How to Tie the Output of Two Subprocesses Together
Why Doesn't Relative_Require Work on Ruby 1.8.6
Undefined Method 'Name' for "Actionmailer":String
How to Find Gems That Depend on a Given Gem
How to Store an Instance Variable Across Multiple Actions in a Controller
Slicing Params Hash for Specific Values
How to Batch Convert Mp4 Files to Ogg with Ffmpeg Using a Bash Command or Ruby