returning array without specific elements in ruby - 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.

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

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

Find Value in Array of ActiveRecord Objects vs. Find Value from Repeated DB Calls

I would just like to return true, if my Array of Contact(s) (model) contains a Contact with id equal to some value. For example:
#contacts = Contact.all
#someval = "alskjdf"
find_val(#contacts, #someval)
def find_val(contacts, val)
#contact.each do |c|
if c.id == val
return true
end
end
return false
end
I have to do this repeatedly in my app (at most about 100 times for this particular actions), in order to exclude some data from an external API that has a list of contacts. Is this going to be too expensive?
I thought I might be able to do something faster, similar to ActiveRecord find on the array after it's been pulled down from the db, but can't figure that out. Would it be too expensive to call ActiveRecord like this?
Contacts.find_by_id(#someval)
The above line would have to be called hundreds of times... I figure iterating through the array would be less expensive. Thanks!
The best approach would be to index the contacts in a hash, using the contact id as the key after you retrieve them all from the db:
contacts = Contact.all.inject({}) {|hash, contact| hash[contact.id] = contact; hash }
Then you can easily get a contact with contact[id] in a performant way.
One way to reduce the amount of code you have to write to search the array is to open the array class and make a custom instance method:
class Array
def haz_value?(someval)
if self.first.respond_to? :id
self.select { |contact| contact.id == someval }.length > 0
else
false
end
end
end
Then, you can call #contacts.haz_value? #someval. In terms of efficiency, I haven't done a comparison, but both ways use Array's built-in iterators. It would probably be faster to create a stored procedure in your database and call it through ActiveRecord, here is how you can do that.

Is there a concise way to return the numerical iterator in a loop in Ruby?

It seems like there should be a one-liner way to iterate over season and return the last season when show.has_season? evaluates to false.
def last_season(show)
season = 1
season += 1 while show.has_season?(season)
return season
end
Edit: has_season? involves an HTTP GET call, so I can't really see a clean way around iterating using it.
What you're doing is sort of a roundabout way of getting to an answer. What is the has_season? method doing? Would it make sense for your show object to have an array of seasons? Then you could just do something like:
class Show
attr_accessor :seasons
def initialize
#seasons = []
end
def last_season
seasons.last
end
end
show = Show.new
show.seasons = [1,2,3,4,5,6]
show.last_season # => 6
One solution would be to use something like this:
def last_season(show)
(1..1.0/0.0).find {|season| not show.has_season?(season)|
end
But I feel that the class representing show should provide that last_season method and there is likely to be a way to compute it without having to bruteforce through possible numbers of seasons.
In order for a show to respond to has_season? it must already know its own seasons.
The last_season? method should be part of the Show class. A Show would have either an enumeration or a max_season-like value, and it should just return the highest value or the max season.

How to improve the way I browse an array with .each while trying to keep track of the index ("i") using Ruby?

Let's say I'm doing a simple .each but I still want to keep the position in the loop, I can do:
i = 0
poneys.each do |poney|
#something involving i
#something involving poney
i = i + 1
end
This doesn't look very elegant to me. So I guess I could get rid of the .each:
for i in 0..poneys.size-1 do
#something involving i
end
... or something similar with a different syntax.
The problem is that if I want to access the object I have to do:
for i in 0..poneys.size-1 do
poney = poneys[i]
#something involving i
#something involving poney
end
... and that's not very elegant either.
Is there a nice and clean way of doing this ?
You can use Enumerable#each_with_index
From the official documentation:
Calls block with two arguments, the
item and its index, for each item in
enum.
hash = Hash.new
%w(cat dog wombat).each_with_index do |item, index|
hash[item] = index
end
hash #=> {"cat"=>0, "wombat"=>2, "dog"=>1}
Depends what do you do with poneys :) Enumerable#inject is also a nice one for such things:
poneys.inject(0) do |i, poney|
i += 1; i
end
I learned a lot about inject from http://blog.jayfields.com/2008/03/ruby-inject.html which is great article.

Resources