Method for padding an array in Ruby - ruby

Here's what I have now and it is somewhat working:
def padding(a, b, c=nil)
until a[b-1]
a << c
end
end
This is when it works:
a=[1,2,3]
padding(a,10,"YES")
=>[1, 2, 3, "YES", "YES", "YES", "YES", "YES", "YES", "YES"]
a[1,2,3]
padding(a,10,1)
=>[1, 2, 3, 1, 1, 1, 1, 1, 1, 1]
But it crashes when I do not enter a value for "c"
a=[1,2,3]
padding(a,10)
Killed
How should I append this to avoid a crash?
Additionally, how would you suggest changing this method to use it as follows:
[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"]
I've seen other padding methods on SO, but they don't seem to be working as intended by the authors. So, I decided to give making my own a shot.

Do you know Array#fill method :-
It does, what you exactly looking for. If it exist, why you want your own.
arup#linux-wzza:~> pry
[1] pry(main)> a=[1,2,3]
=> [1, 2, 3]
[2] pry(main)> a.fill('YES', 3...10)
=> [1, 2, 3, "YES", "YES", "YES", "YES", "YES", "YES", "YES"]
[3] pry(main)>
You can fill your array, whatever way you want. It is a cool implementation. Give it a try.
Read it in your console :
arup#linux-wzza:~> ri Array#fill
= Array#fill
(from ruby site)
------------------------------------------------------------------------------
ary.fill(obj) -> ary
ary.fill(obj, start [, length]) -> ary
ary.fill(obj, range ) -> ary
ary.fill { |index| block } -> ary
ary.fill(start [, length] ) { |index| block } -> ary
ary.fill(range) { |index| block } -> ary
------------------------------------------------------------------------------
The first three forms set the selected elements of self (which may be the
entire array) to obj.
A start of nil is equivalent to zero.
A length of nil is equivalent to the length of the array.
The last three forms fill the array with the value of the given block, which
is passed the absolute index of each element to be filled.
Negative values of start count from the end of the array, where -1 is the last
element.
a = [ "a", "b", "c", "d" ]
a.fill("x") #=> ["x", "x", "x", "x"]
a.fill("z", 2, 2) #=> ["x", "x", "z", "z"]
a.fill("y", 0..1) #=> ["y", "y", "z", "z"]
a.fill { |i| i*i } #=> [0, 1, 4, 9]
a.fill(-2) { |i| i*i*i } #=> [0, 1, 8, 27]

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.

Arup has nailed it, but here's another way:
def padding(a,b,c)
[*a, *[c]*b]
end
a=[1,2,3]
padding(a,5,"YES")
#=> [1, 2, 3, "YES", "YES", "YES", "YES", "YES"]

The problem is that nil is evaluated as false, so until a[b-1] is never true when a[b-1] contains nil... so you loop forever until you're out of memory.
better to do...
def padding(a, b, c=nil)
until a.size >= b
a << c
end
end
EDIT
(yes, Arup's answer is pretty neat)
You can do this as a one-liner, which is a bit more compact...
def padding(a, b, c=nil)
a << c until a.size >= b
end

To specifically implement your padding method on Array:
module Padding
refine Array do
def padding(new_length, element=nil)
if self.size < new_length
self.concat(Array.new(new_length - self.size, element))
end
end
end
end
using Padding
puts [1,2,3].padding(10).inspect
# => [1, 2, 3, nil, nil, nil, nil, nil, nil, nil]
puts [1,2,3].padding(10, "YES").inspect
# => [1, 2, 3, "YES", "YES", "YES", "YES", "YES", "YES", "YES"]
EDIT: Forgot about Array#fill. Arup's answer is cool (even if you need to say fill(3, 7) instead of fill(-1, 10), as the latter gives the wrong result). It would have been better to use it instead of concat(Array.new(...)). Eh well. :)

Related

Why "select" does not return true value or is it?

[1,2,5,8,3].collect{|i| i.to_s} #=> ["1", "2", "5", "8", "3"]
Whereas
[1,2,5,8,3].select{|i| i.to_s} #=> [1, 2, 5, 8, 3]
As per ruby-doc select => "Returns a new array containing all elements of ary for which the given block returns a true value."
Isn't the true value here should be i.to_s value
In ruby anything order than nil or false is true
So:
[1,2,5,8,3].select{|i| i.to_s} is equivalent to [1,2,5,8,3].select{|i| true }
which would both evaluate to:
[1,2,5,8,3].select{|i| i.to_s} #=> [1, 2, 5, 8, 3]
[1,2,5,8,3].select{|i| true } #=> [1, 2, 5, 8, 3]
as you said in the question
select => "Returns a new array containing all elements of ary for
which the given block returns a true value.
So select would return the original array since the block always evaluates to true.
However collect
Returns a new array with the results of running block once for every element in enum.
So:
[1,2,5,8,3].collect{|i| i.to_s} #=> ["1", "2", "5", "8", "3"]
[1,2,5,8,3].collect{|i| true } #=> [true, true, true, true, true]
Because #select the only selects the values from the array, when block is evaluated to non-false, and returns the new array:
{|i| i.to_s } # => false|nil or non-false|nil
while #collect generates the new array by appying block to each of current array values:
{|i| i.to_s } # => i.to_s => "String"
You can think of #collect as a map operation and #select as a filter, hence #select's return value is always a subset of the initial array.

How to use an enumerator

In the Ruby Array Class documentation, I often find:
If no block is given, an enumerator is returned instead.
Why would I not pass a block to #map? What would be the use of my doing just:
[1,2,3,4].map
instead of doing:
[1,2,3,4].map{ |e| e * 10 } # => [10, 20, 30, 40]
Can someone show me a very practical example of using this enumerator?
Good question.
What if we want to do multiple things with the enumerator that is created? We don't want to process it now, because it means we may need to create another later?
my_enum = %w[now is the time for all good elves to get to work].map # => #<Enumerator: ["now", "is", "the", "time", "for", "all", "good", "elves", "to", "get", "to", "work"]:map>
my_enum.each(&:upcase) # => ["NOW", "IS", "THE", "TIME", "FOR", "ALL", "GOOD", "ELVES", "TO", "GET", "TO", "WORK"]
my_enum.each(&:capitalize) # => ["Now", "Is", "The", "Time", "For", "All", "Good", "Elves", "To", "Get", "To", "Work"]
The main distinction between an Enumerator and most† other data structures in the Ruby core library (Array, Hash) and standard library (Set, SortedSet) is that an Enumerator can be infinite. You cannot have an Array of all even numbers or a stream of zeroes or all prime numbers, but you can definitely have such an Enumerator:
evens = Enumerator.new do |y|
i = -2
y << i += 2 while true
end
evens.take(10)
# => [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
zeroes = [0].cycle
zeroes.take(10)
# => [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
So, what can you do with such an Enumerator? Well, three things, basically.
Enumerator mixes in Enumerable. Therefore, you can use all Enumerable methods such as map, inject, all?, any?, none?, select, reject and so forth. Just be aware that an Enumerator may be infinite whereas map returns an Array, so trying to map an infinite Enumerator may create an infinitely large Array and take an infinite amount of time.
There are wrapping methods which somehow "enrich" an Enumerator and return a new Enumerator. For example, Enumerator#with_index adds a "loop counter" to the block and Enumerator#with_object adds a memo object.
You can use an Enumerator just like you would use it in other languages for external iteration by using the Enumerator#next method which will give you either the next value (and move the Enumerator forward) or raise a StopIteration exception if the Enumerator is finite and you have reached the end.
† Eg., an infinite range: (1..1.0/0)
The feature of returning a enumerable when no block is given is mostly used when chaining functions from the enumerable class together. Like this:
abc = %w[a b c]
p abc.map.with_index{|item, index| [item, index]} #=> [["a", 0], ["b", 1], ["c", 2]]
edit:
I think my own understanding of this behavior is a bit too limited in order to give a proper understanding of the inner workings of Ruby. I think the most important thing to note is that arguments are passed on in the same way they are for Procs. Thus if an array is passed in, it will be automatically 'splatted' (any better word for this?). I think the best way to get an understanding is to just use some simple functions returning enumerables and start experimenting.
abc = %w[a b c d]
p abc.each_slice(2) #<Enumerator: ["a", "b", "c", "d"]:each_slice(2)>
p abc.each_slice(2).to_a #=> [["a", "b"], ["c", "d"]]
p abc.each_slice(2).map{|x| x} #=> [["a", "b"], ["c", "d"]]
p abc.each_slice(2).map{|x,y| x+y} #=> ["ab", "cd"]
p abc.each_slice(2).map{|x,| x} #=> ["a", "c"] # rest of arguments discarded because of comma.
p abc.each_slice(2).map.with_index{|array, index| [array, index]} #=> [[["a", "b"], 0], [["c", "d"], 1]]
p abc.each_slice(2).map.with_index{|(x,y), index| [x,y, index]} #=> [["a", "b", 0], ["c", "d", 1]]
In addition to hirolau's answer, there is another method lazy that you can combine to modify the enumerator.
a_very_long_array.map.lazy
If map always took a block, then there would have to be another method like map_lazy, and similarly for other iterators to do the same thing.
I guess sometimes you want to pass the Enumerator to another method, despite where this Enumerator came from: map, slice, whatever:
def report enum
if Enumerator === enum
enum.each { |e| puts "Element: #{e}" }
else
raise "report method requires enumerator as parameter"
end
end
> report %w[one two three].map
# Element: one
# Element: two
# Element: three
> report (1..10).each_slice(2)
# Element: [1, 2]
# Element: [3, 4]
# Element: [5, 6]
# Element: [7, 8]
# Element: [9, 10]
Enumerator A class which allows both internal and external iteration
=> array = [1,2,3,4,5]
=> array.map
=> #<Enumerator: [2, 4, 6, 8, 10]:map>
=> array.map.next
=> 2
=> array.map.next_values
=> [0] 2

Reposition an element to the front of an array in Ruby

Even coming from javascript this looks atrocious to me:
irb
>> a = ['a', 'b', 'c']
=> ["a", "b", "c"]
>> a.unshift(a.delete('c'))
=> ["c", "a", "b"]
Is there a more legible way placing an element to the front of an array?
Edit my actual code:
if #admin_users.include?(current_user)
#admin_users.unshift(#admin_users.delete(current_user))
end
Maybe this looks better to you:
a.insert(0, a.delete('c'))
Maybe Array#rotate would work for you:
['a', 'b', 'c'].rotate(-1)
#=> ["c", "a", "b"]
This is a trickier problem than it seems. I defined the following tests:
describe Array do
describe '.promote' do
subject(:array) { [1, 2, 3] }
it { expect(array.promote(2)).to eq [2, 1, 3] }
it { expect(array.promote(3)).to eq [3, 1, 2] }
it { expect(array.promote(4)).to eq [1, 2, 3] }
it { expect((array + array).promote(2)).to eq [2, 1, 3, 1, 2, 3] }
end
end
sort_by proposed by #Duopixel is elegant but produces [3, 2, 1] for the second test.
class Array
def promote(promoted_element)
sort_by { |element| element == promoted_element ? 0 : 1 }
end
end
#tadman uses delete, but this deletes all matching elements, so the output of the fourth test is [2, 1, 3, 1, 3].
class Array
def promote(promoted_element)
if (found = delete(promoted_element))
unshift(found)
end
self
end
end
I tried using:
class Array
def promote(promoted_element)
return self unless (found = delete_at(find_index(promoted_element)))
unshift(found)
end
end
But that failed the third test because delete_at can't handle nil. Finally, I settled on:
class Array
def promote(promoted_element)
return self unless (found_index = find_index(promoted_element))
unshift(delete_at(found_index))
end
end
Who knew a simple idea like promote could be so tricky?
Adding my two cents:
array.select{ |item| <condition> } | array
Pros:
Can move multiple items to front of array
Cons:
This will remove all duplicates unless it's the desired outcome.
Example - Move all odd numbers to the front (and make array unique):
data = [1, 2, 3, 4, 3, 5, 1]
data.select{ |item| item.odd? } | data
# Short version:
data.select(&:odd?) | data
Result:
[1, 3, 5, 2, 4]
Another way:
a = [1, 2, 3, 4]
b = 3
[b] + (a - [b])
=> [3, 1, 2, 4]
If by "elegant" you mean more readable even at the expense of being non-standard, you could always write your own method that enhances Array:
class Array
def promote(value)
if (found = delete(value))
unshift(found)
end
self
end
end
a = %w[ a b c ]
a.promote('c')
# => ["c", "a", "b"]
a.promote('x')
# => ["c", "a", "b"]
Keep in mind this would only reposition a single instance of a value. If there are several in the array, subsequent ones would probably not be moved until the first is removed.
In the end I considered this the most readable alternative to moving an element to the front:
if #admin_users.include?(current_user)
#admin_users.sort_by{|admin| admin == current_user ? 0 : 1}
end
If all the elements in the array are unique you can use array arithmetic:
> a = ['a', 'b', 'c']
=> ["a", "b", "c"]
> a -= "c"
=> ["a", "b"]
> a = ["c"] + a
=> ["c", "a", "b"]
Building on above:
class Array
def promote(*promoted)
self - (tail = self - promoted) + tail
end
end
[1,2,3,4].promote(5)
=> [1, 2, 3, 4]
[1,2,3,4].promote(4)
=> [4, 1, 2, 3]
[1,2,3,4].promote(2,4)
=> [2, 4, 1, 3]

To find the integer (Fixnum) values in ruby array

I have an array [1, 2, "3", "4", "1a", "abc", "a"] with
pure integers (1, 2),
string formatted integers ("1", "2"),
strings ("a", "b"), and
mixed string numbers ("1a", "2s").
From this, I need to pick up only the integers (including string formatted) 1, 2, "3", "4".
First I tried with to_i:
arr = [1, 2, "3", "4", "1a", "abc", "a"]
arr.map {|x| x.to_i}
# => [1, 2, 3, 4, 1, 0, 0]
but this one converts "1a" to 1, which I don't expect.
Then I tried Integer(item):
arr.map {|x| Integer(x) } # and it turned out to be
# => ArgumentError: invalid value for Integer(): "1a"
Now I am out of straight conversion options here. Finally, I decided to do this way, which converts the value to_i and to_s. So "1" == "1".to_i.to_s is an integer, but not "1a" == "1a".to_i.to_s and "a" == "a".to_i.to_s
arr = arr.map do |x|
if (x == x.to_i.to_s)
x.to_i
else
x
end
end
and
ids, names= arr.partition { |item| item.kind_of? Fixnum }
Now I got the arrays of integers and strings. Is there a simple way to do this?
Similar solution as provided by #maerics, but a bit slimmer:
arr.map {|x| Integer(x) rescue nil }.compact
class Array
def to_i
self.map {|x| begin; Integer(x); rescue; nil; end}.compact
end
end
arr = [1, 2, "3", "4", "1a", "abc", "a"]
arr.to_i # => [1, 2, 3, 4]
something like this:
a = [1,2,"3","4","1a","abc","a"]
irb(main):005:0> a.find_all { |e| e.to_s =~ /^\d+$/ }.map(&:to_i)
=> [1, 2, 3, 4]
Hey, thanks awakening my ruby. Here is my go at this problem:
arr=[1,2,"3","4","1a","abc","a"]
arr.map {|i| i.to_s}.select {|s| s =~ /^[0-9]+$/}.map {|i| i.to_i}
//=> [1, 2, 3, 4]
I noticed most of the answer so far changes the value of "3" and "4" to actual integers.
>> array=[1, 2, "3", "4", "1a", "abc", "a", "a13344a" , 10001, 3321]
=> [1, 2, "3", "4", "1a", "abc", "a", "a13344a", 10001, 3321]
>> array.reject{|x| x.to_s[/[^0-9]/] }
=> [1, 2, "3", "4", 10001, 3321]
#OP, I have not tested my solution exhaustively, but so far it seems to work (of course its done according to provided sample ), so please test thoroughly yourself.
How about this?
[1,2,"3","4","1a","abc","a"].select{|x| x.to_i.to_s == x.to_s}
# => [1, 2, "3", "4"]
Looks pretty simple
arr.select{ |b| b.to_s =~ /\d+$/ }
# or
arr.select{ |b| b.to_s[/\d+$/] }
#=> [1, 2, "3", "4"]

How to return a part of an array in Ruby?

With a list in Python I can return a part of it using the following code:
foo = [1,2,3,4,5,6]
bar = [10,20,30,40,50,60]
half = len(foo) / 2
foobar = foo[:half] + bar[half:]
Since Ruby does everything in arrays I wonder if there is something similar to that.
Yes, Ruby has very similar array-slicing syntax to Python. Here is the ri documentation for the array index method:
--------------------------------------------------------------- Array#[]
array[index] -> obj or nil
array[start, length] -> an_array or nil
array[range] -> an_array or nil
array.slice(index) -> obj or nil
array.slice(start, length) -> an_array or nil
array.slice(range) -> an_array or nil
------------------------------------------------------------------------
Element Reference---Returns the element at index, or returns a
subarray starting at start and continuing for length elements, or
returns a subarray specified by range. Negative indices count
backward from the end of the array (-1 is the last element).
Returns nil if the index (or starting index) are out of range.
a = [ "a", "b", "c", "d", "e" ]
a[2] + a[0] + a[1] #=> "cab"
a[6] #=> nil
a[1, 2] #=> [ "b", "c" ]
a[1..3] #=> [ "b", "c", "d" ]
a[4..7] #=> [ "e" ]
a[6..10] #=> nil
a[-3, 3] #=> [ "c", "d", "e" ]
# special cases
a[5] #=> nil
a[6, 1] #=> nil
a[5, 1] #=> []
a[5..10] #=> []
If you want to split/cut the array on an index i,
arr = arr.drop(i)
> arr = [1,2,3,4,5]
=> [1, 2, 3, 4, 5]
> arr.drop(2)
=> [3, 4, 5]
You can use slice() for this:
>> foo = [1,2,3,4,5,6]
=> [1, 2, 3, 4, 5, 6]
>> bar = [10,20,30,40,50,60]
=> [10, 20, 30, 40, 50, 60]
>> half = foo.length / 2
=> 3
>> foobar = foo.slice(0, half) + bar.slice(half, foo.length)
=> [1, 2, 3, 40, 50, 60]
By the way, to the best of my knowledge, Python "lists" are just efficiently implemented dynamically growing arrays. Insertion at the beginning is in O(n), insertion at the end is amortized O(1), random access is O(1).
Ruby 2.6 Beginless/Endless Ranges
(..1)
# or
(...1)
(1..)
# or
(1...)
[1,2,3,4,5,6][..3]
=> [1, 2, 3, 4]
[1,2,3,4,5,6][...3]
=> [1, 2, 3]
ROLES = %w[superadmin manager admin contact user]
ROLES[ROLES.index('admin')..]
=> ["admin", "contact", "user"]
another way is to use the range method
foo = [1,2,3,4,5,6]
bar = [10,20,30,40,50,60]
a = foo[0...3]
b = bar[3...6]
print a + b
=> [1, 2, 3, 40, 50 , 60]
I like ranges for this:
def first_half(list)
list[0...(list.length / 2)]
end
def last_half(list)
list[(list.length / 2)..list.length]
end
However, be very careful about whether the endpoint is included in your range. This becomes critical on an odd-length list where you need to choose where you're going to break the middle. Otherwise you'll end up double-counting the middle element.
The above example will consistently put the middle element in the last half.

Resources