Concatenating multiple arrays in ruby - ruby

I'm trying to make a method that accepts a nested array. From that nested array, I need to return all possible combinations that can be made by the sub-arrays. I have been working on it for hours now and I still can't get it to work.
It's like concatenating each element of a sub_array with each element from the other sub_arrays.
example:
mega_array = [["a","b"],["c","d"],["e","f"]]
my_method(mega_array)
=> ["ace","acf","ade","adf","bce","bcf","bde","bdf"]
This would have been accomplished by the following code:
mega_array[0].each do |first|
mega_array[1].each do |second|
mega_array[2].each do |third|
puts first + second + third
end
end
end
Unfortunately, the number of subarrays can vary. This is where I'm stuck. Tried to do some recursive techniques but I still don't get it right.
Help will be greatly appreciated. I need to make this work with the vanilla Ruby that comes with Leopard and up. It's 1.8.7, right?
Thanks.

>> mega_array[0].product(*mega_array[1..-1]).map(&:join)
=> ["ace", "acf", "ade", "adf", "bce", "bcf", "bde", "bdf"]

Related

Why can't I get Array#slice to work the way I want?

I have a big Array of AR model instances. Let's say there are 20K entries in the array. I want to move through that array a chunk of 1,000 at a time.
slice_size = 1000
start = 0
myarray.slice(start, slice_size) do |slice|
slice.each do |item|
item.dostuff
end
start+=slice_size
end
I can replace that whole inner block with just:
puts "hey"
and not see a thing in the console. I have tried this 9 ways from Sunday. And I've done it successfully before, just can't remember where. And I have RTFM. Can anyone help?
The problem is that slice does not take a block, but you are passing it a block, and trying to do something in it, which is ignored. If you do
myarray.slice(start, slice_size).each do |slice|
...
end
then it should work.
But to do it that way is not Ruby-ish. A better way is
myarray.each_slice(slice_size) do |slice|
...
end
If the array can be destroyed, you could do it like this:
((myarray.size+slice_size-1)/slice_size).times.map {myarray.shift(slice_size)}
If not:
((myarray.size+slice_size-1)/slice_size).times.map { |i|
myarray.slice(i*slice_size, slice_size) }
You can use:
Enumerable#each_slice(n) which takes n items at a time;
Array#in_groups_of(n) (if this is Rails) which works like each_slice but will pad the last group to guarantee the group size remains constant;
But I recommend using ActiveRecord's built-in Model.find_each which will batch queries in the DB layer for better performance. It defaults to 1000, but you can specify the batch size. See http://guides.rubyonrails.org/active_record_querying.html#retrieving-multiple-objects-in-batches for more detail.
Example from the guide:
User.find_each(batch_size: 5000) do |user|
NewsLetter.weekly_deliver(user)
end

returning array without specific elements in ruby

I looked really hard in http://www.ruby-doc.org/core-2.1.2/Array.html but I couldn't find a quick functionality to this behaviour:
arr = [1,2,3,4,5,6]
arr.without(3,6) #=> [1,2,4,5]
I know I can write my own function/monkey-patch ruby/add a class method/write it in a few lines.
Is there a way to do this in a ruby way?
you can use subtraction :
arr - [3,6]
EDIT
if you really wanted you could alias this method
class Array
alias except -
end
then you can use:
arr.except [3,6]
This got added in Rails 5 :)
https://github.com/rails/rails/issues/19082
module Enumerable
def without(*elements)
reject { |element| element.in?(elements) }
end
end
it's just aesthetics, but it makes sense for the brain
There is another way using reject. But it is not cleaner than -
arr.reject{|x| [3,6].include? x}
Just in case anyone else comes across this and is looking for a way to delete elements from an array based on a conditional: you can use delete_if.
For example, I have a list of customers and want to merge any customers that have duplicate emails. After doing a query to get a list of all emails with the total count number for each email, I can then delete all of them that only appear once:
emails = Customer.select('count(email) as num_emails, email').group('email')
emails.delete_if { |email| email.num_emails.to_i == 1 }
The end result is I have a list of all customer emails that appear multiple times in the database.

Ruby: add a simple function to Mylist < Array

I'm struggling with some database migration stuff, and this is what I want to do:
I created a Class Mylist < Array with a method each_hash added, this method needs to act just like the Array's each, that means the two calls are equal:
list = Mylist.new
list.each |d|
...
end
list.each_hash |d|
...
end
I have tried here and there but it does not work, any help would be appreciated!
Thanks #Charles Caldwell, works excellent
If you want the each_hash to be the exact same thing as each, you could do alias :each_hash :each. It would make a call to each_hash to actually be a call to each. Would that be an option in your case? – Charles Caldwell

help with a simple method

Hi I'm trying to solve the exercise from https://github.com/alexch/learn_ruby
I must write a method which should "multiplies two numbers" and "multiplies an array of numbers". I'm fresh to ruby and solved it, with only one method like this:
def multi(*l)
sum = 1
l.flatten! if l.is_a? Array
l.each{|i| sum = sum*i}
return sum
end
I'm sure there are better ways, so how can I improve this method? to a more ruby like syntax :)
The if l.is_a? Array is not necessary because the way multi is define, l will always be an array.
The pattern
result = starting_value
xs.each {|x| result = result op x}
result
can be written more succinctly using xs.inject(starting_value, :op).
So you can write your code as:
def multi(*l)
l.flatten.inject(1, :*)
end
If you're ok, with calling the method as multi(*array) instead of multi(array) to multiply an array, you can leave out the flatten, as well.

Sorting a Ruby array

I am trying to sort large inputs in the fastest way in ascending order. The code is something like this:
t=gets
ti=t.to_i
r=[]
for i in(0..ti)
k=gets
r[i]=k.to_i
end
r.sort_by{|x| -x.last}
This is giving me an error saying undefined method 'last' for nil:nilclass <nomethoderror>
from tsort.rb: in sort_by
from tsort.rb in 'each'
from tsort.rb in 'sort_by'
I don't know where am I wrong.
That's what I have tried for sorting an array...which is r[] which has all the numbers in t! Can anyone please help.
My inputs are less than 10^6!
I can't reproduce your exact error, I get undefined method 'last' for n:Fixnum (NoMethodError). That makes sense, because you're calling the last method on x, which will hold the values of your Array r, all Fixnums, which do not have a last method.
It should work if you replace the last line with:
r.sort
The sort method will sort your Array in ascending order by default.
If you want to sort a list of integers taken from STDIN I suggest something like the following:
lines = STDIN.readlines.map { |x| x.strip.to_i }.sort
puts lines.join(', ')
It's cleaner, more rubyish and faster (read the documentation for Enumerable.sort_by to see why sort is a better alternative to sort_by).
I also see your code expects a number that says how many lines to read. You can get the same behavior by modifying the example above as follows:
line_count = gets.strip.to_i
lines = (1..line_count).collect { gets.strip.to_i }.sort
puts lines.join(', ')
Try the sort function on Array's think it does what you need.

Resources