How do you double number in ruby for an iterator - ruby-on-rails

Need to double each value in my array. I know double is not a command, but not sure what else to use.
odds = [1,3,5,7,9]
array.each do |x|
x += double
print "#{x}"
end

Use Array#map to create a new array
odds = [1,3,5,7,9]
arr = odds.map{|x| x*2}
arr.inspect
# => [2,6,10,14,18]
To modify the same array use Array#map!
odds = [1,3,5,7,9]
odds.map!{|x| x*2}
odds.inspect
# => [2,6,10,14,18]

Do you mean 'double' as in multiply by 2, or double as in duplicate?
array = [1,3,5,7,9]
array.each { |x| print "#{x*2}"; }
But you probably want either a new array, or to map your existing array,
result = []
result = array.map { |x| x*2 }
#or
result = array.map! { |x| x*2 }
Here is an example of duplicate,
result = []
array.map { |x| result << x; result << x; } #duplicate
see here: http://www.natontesting.com/2011/01/01/rubys-each-select-and-reject-methods/

Doing the Simplest Thing Possible
The simplest thing to do is to simply iterate over your array with Array#map and Kernel#p. For example:
odds = [1, 3, 5, 7, 9]
odds.map { |i| p i*2 }
Defining a Custom Method
If you need more control, you can create a custom method that handles a block or returns an enumerator. For example:
def double *array
array.flatten!
block_given? ? array.map { |i| yield i*2 } : array.map { |i| i*2 }.to_enum
end
enumerator = double 1, 2, 3
#=> #<Enumerator: ...>
enumerator.each { |i| p i }
#=> [2, 4, 6]
double(1, 2, 3) { |i| p i }
#=> [2, 4, 6]
This is probably overkill for your use case, but it's a useful technique to know if you want to work with enumerators and blocks. Hope it helps!

The way that I have found to do it is to times / equal it by 2. For example:
odds = [1,3,5,7,9]
odds.each do |x|
x *= 2
print x
end

Related

Efficient way to subtract arrays and get index of resulting subarray

Lets say I have the following arrays:
arr1 = [
['a', 'b'],
['c', 'd'],
['e', 'f']
]
arr2 = [
['g', 'h'],
['i', 'k'],
['a', 'b']
]
I want to find the elements in arr1 that do not exist in arr2 and the index of the elements in arr1
I can do this with the following but this isn't very efficient and is not a pretty solution. There can also be many elements in the arrays so this does not scale. Is there a better way to do this?
diff = arr1 - arr2
diff_with_index = diff.map { |x| { index: arr1.index(x), values: x } }
print diff_with_index
# [{:index=>1, :values=>["c", "d"]}, {:index=>2, :values=>["e", "f"]}]
When you have to do multiple include? checks, the most efficient way is to turn one of the lists into a set or hash beforehand, so you can have O(1) lookup time, so something like this:
require 'set'
arr2_set = Set.new(arr2)
arr1.each_index.select { |idx| !arr2_set.include?(arr1[idx]) }
Here is one way.
i1 = (0..arr1.size-1).to_a
#=> [0, 1, 2]
h1 = arr1.zip(i1).to_h
#=> {["a", "b"]=>0, ["c", "d"]=>1, ["e", "f"]=>2}
i1 - arr2.map { |a| h1[a] }
#=> [1, 2]
Note that
arr2.map { |a| h1[a] }
#=> [nil, nil, 0]

Remove array elements at indices non destructively

Let's say you have something like this:
my_array = ['some_rather', 'long_named', 'array_element', 'entry']
I want to remove arbitrary entries by index from my_array without changing it and I want the filtered (i.e. array with indices removed) to be returned from my call. Furthermore, I want to avoid chaining 4 separate calls and write a block doing so.
Example:
filtered_array = my_array.drop_indices(1,3)
You could chain Enumerable's with_index onto Array's reject method to do what you want, though this might violate your desire to not chain separate method calls or write a block to do this:
my_array = ['some_rather', 'long_named', 'array_element', 'entry', 'long_named']
indices_to_remove = [1, 3]
filtered = my_array.reject.with_index { |_, index| indices_to_remove.include?(index) }
p filtered # => ["some_rather", "array_element", "long_named"]
p my_array # => ["some_rather", "long_named", "array_element", "entry", "long_named"]
If this isn't acceptable, the only other thing I can think of right now, to keep duplicate items (as noted in my comment to your solution), is to change from indices_to_remove to indices_to_keep:
my_array = ['some_rather', 'long_named', 'array_element', 'entry', 'long_named']
indices_to_remove = [1, 3]
indices_to_keep = [*(0...my_array.length)] - indices_to_remove
filtered = my_array.values_at(*indices_to_keep)
p filtered # => ["some_rather", "array_element", "long_named"]
p my_array # => ["some_rather", "long_named", "array_element", "entry", "long_named"]
For Arrays with duplicate Elements the best I know is:
array = [0,15,8,15,8]
indices_to_remove = [1,4]
res = array.reject.with_index{ |_,i| indices_to_remove.include?(i) }
returns
[0,8,15]
Additionally for arrays with unique entries such as a set of users
(using variable definitions from the question)
filtered_array = my_array - my_array.values_at(1,3)
Bonus, if your indices are inside an array themselves:
indices_to_remove = [1,3]
filtered_array = my_array - my_array.values_at(*indices_to_remove)
I think this is rather descriptive, not awkward and not shorter than needed.
One more possible solution with some addition, now it's also will work with negative indexes:
array = %w( a b c d e f )
indexes = [1, 2, -1, -9, -6, 6]
def array_except(array, *indexes)
indexes = indexes.map { |e| e.negative? ? e + array.length : e }
array.values_at(*((0...array.length).to_a - indexes))
end
array_except(array, *indexes)
=> ["d", "e"]
array_except(array, 0, -1)
=> ["b", "c", "d", "e"]

Using .map function to create hashes

I have an array [5,2,6,4] and I would like to create a structure such as the first minus the second etc until the last row.
I have tried using map, but not sure how to proceed since i might need indxes.
I would like to store the result in something that looks like:
{1 => (5, 2, 3), 2 =>(2,6,-4), 3 => (6,4,2)}
So an array of x should return x-1 hashes.
Anybody knows how to do? should be a simple one.
Thank you.
First, you want to work with the array elements in pairs: 5,2, 2,6, ... That means you want to use each_cons:
a.each_cons(2) { |(e1, e2)| ... }
Then you'll want the index to get the 1, 2, ... hash keys; that suggests throwing a Enumerator#with_index into the mix:
a.each_cons(2).with_index { |(e1, e2), i| ... }
Then you can use with_object to get the final piece (the hash) into play:
a.each_cons(2).with_index.with_object({}) { |((e1, e2), i), h| h[i + 1] = [e1, e2, e1 - e2] }
If you think all the parentheses in the block's arguments are too noisy then you can do it in steps rather than a single one-liner.
You can use each_index:
a = [5, 2, 6, 4]
h = {}
a[0..-2].each_index { |i| h[i+1] = [a[i], a[i+1], a[i] - a[i+1]] }
h
=> {1=>[5, 2, 3], 2=>[2, 6, -4], 3=>[6, 4, 2]}
Try to use
each_with_index
Suppose you have an array:
arr = [3,[2,3],4,5]
And you want to covert with hash(key-value pair). 'Key' denotes an index of an array and 'value' denotes value of an array. Take a blank hash and iterate with each_with_index and pushed into the hash and finally print the hash.
Try this:
hash={}
arr.each_with_index do |val, index|
hash[index]=val
end
p hash
Its output will be:
{0=>3, 1=>[2, 3], 2=>4, 3=>5}
If you want that index always starts with 1 or 2 etc then use
arr.each.with_index(1) do |val, index|
hash[index] = val
end
Output will be:
{1=>3, 2=>[2, 3], 3=>4, 4=>5}

Merge two arrays into a Hash

My desired outcome is something like this:
{date: 12/02/2014, minutes: 36}
I'm scraping with Nokogiri using:
dates = doc.css('td:nth-child(3)')
minutes = doc.css('td:nth-child(10)')
Then I do some filtering and pushing results into arrays:
dates.each do |x|
if x.text.length == 10
date_array << x.text
end
end
minutes.each do |x|
minutes_array << x.text
end
How can I zip these two arrays together to create my desired outcome?
i've tried something like this, but it's not quite right (gives me {"2013-10-29"=>"32:14"} )
result = Hash[date_array.zip(minutes_array)]
or even something like this:
result = Hash[date_array.zip(minutes_array).map {|d, m| {:date => d, :minutes => m}}
but i get this error: wrong element type Hash at 163
i've also tinkered with .flatten but to no avail. Can anybody help?
assuming you have 2 equal length arrays x and y
x = [:key1, :key2, :key3]
y = [:value1, :value2, :value3]
z = {}
x.each_with_index { |key,index| z[key] = y[index] }
puts z
=> {:key1=>:value1, :key2=>:value2, :key3=>:value3}
is that what you are looking for?
then maybe this:
x = [:key1, :key2, :key3]
y = [:value1, :value2, :value3]
z = []
x.each_with_index { |key,index| z << { date: key, minutes: y[index]} }
puts z
{:date=>:key1, :minutes=>:value1}
{:date=>:key2, :minutes=>:value2}
{:date=>:key3, :minutes=>:value3}
Stealing from nPn (I can't comment on his answer because I've got no reputation )
Assuming you have
x = [ "date1", "date2", "date3"]
y = [ "time1", "time2", "time3"]
Then you can do:
z = []
x.each_with_index { |k, i| z << { date: k, time: y[i] } }
puts z
=> [ { date: "date1", time: "time1" },
{ date: "date2", time: "time2" },
{ date: "date3", time: "time3" } ]
Is this what you are looking for ?
You are trying to have the same key (date, minutes) for multiple values. You can instead have an array of hash for all those date-minute combos though, with this -
date.zip(minutes).reduce([]) { |memo, combo| memo << Hash[*[:date, :minutes].zip(combo).flatten] }
Here is how it looks -
2.1.5 :035 > date=["10/10,2010","11/10/2010","12/10/2010","13/10/2010","14/10/2010"]
=> ["10/10,2010", "11/10/2010", "12/10/2010", "13/10/2010", "14/10/2010"]
2.1.5 :036 > minutes = [10,20,30,40,50]
=> [10, 20, 30, 40, 50]
2.1.5 :037 > date.zip(minutes).reduce([]) { |memo, combo| memo << Hash[*[:date, :minutes].zip(combo).flatten] }
=> [{:date=>"10/10,2010", :minutes=>10}, {:date=>"11/10/2010", :minutes=>20}, {:date=>"12/10/2010", :minutes=>30}, {:date=>"13/10/2010", :minutes=>40}, {:date=>"14/10/2010", :minutes=>50}]
2.1.5 :038 >
Word of caution - you should really use a Struct, and then create an array of that Struct instances, instead of working on arrays of hashes like this.
If
dates = ["12/02/14", "6/03/14"]
minutes = [12, 19]
then if I've not misunderstood the question, it's just:
dates.zip(minutes).map { |d,m| {date: d, minutes: m} }
#=> [{:date=>"12/02/14", :minutes=>12}, {:date=>"6/03/14", :minutes=>19}]

Creating a new hash with default keys

I want to create a hash with an index that comes from an array.
ary = ["a", "b", "c"]
h = Hash.new(ary.each{|a| h[a] = 0})
My goal is to start with a hash like this:
h = {"a"=>0, "b"=>0, "c"=>0}
so that later when the hash has changed I can reset it with h.default
Unfortunately the way I'm setting up the hash is not working... any ideas?
You should instantiate your hash h first, and then fill it with the contents of the array:
h = {}
ary = ["a", "b", "c"]
ary.each{|a| h[a] = 0}
Use the default value feature for the hash
h = Hash.new(0)
h["a"] # => 0
In this approach, the key is not set.
h.key?("a") # => false
Other approach is to set the missing key when accessed.
h = Hash.new {|h, k| h[k] = 0}
h["a"] # => 0
h.key?("a") # => true
Even in this approach, the operations like key? will fail if you haven't accessed the key before.
h.key?("b") # => false
h["b"] # => 0
h.key?("b") # => true
You can always resort to brute force, which has the least boundary conditions.
h = Hash.new.tap {|h| ["a", "b", "c"].each{|k| h[k] = 0}}
h.key?("b") # => true
h["b"] # => 0
You can do it like this where you expand a list into zero-initialized values:
list = %w[ a b c ]
hash = Hash[list.collect { |i| [ i, 0 ] }]
You can also make a Hash that simply has a default value of 0 for any given key:
hash = Hash.new { |h, k| h[k] = 0 }
Any new key referenced will be pre-initialized to the default value and this will avoid having to initialize the whole hash.
This may not be the most efficient way, but I always appreciate one-liners that reveal a little more about Ruby's versatility:
h = Hash[['a', 'b', 'c'].collect { |v| [v, 0] }]
Or another one-liner that does the same thing:
h = ['a', 'b', 'c'].inject({}) {|h, v| h[v] = 0; h }
By the way, from a performance standpoint, the one-liners run about 80% of the speed of:
h = {}
ary = ['a','b','c']
ary.each { |a| h[a]=0 }
Rails 6 added index_with on Enumerable module. This will help in creating a hash from an enumerator with default or fetched values.
ary = %w[a b c]
hash = ary.index_with(0) # => {"a"=>0, "b"=>0, "c"=>0}
Another option is to use the Enum#inject method which I'm a fan of for its cleanliness. I haven't benchmarked it compared to the other options though.
h = ary.inject({}) {|hash, key| hash[key] = 0; hash}
Alternate way of having a hash with the keys actually added
Hash[[:a, :b, :c].zip([])] # => {:a=>nil, :b=>nil, :c=>nil}
Hash[[:a, :b, :c].zip(Array.new(3, 0))] # => {:a=>0, :b=>0, :c=>0}

Resources