Reject element from array in efficient way - ruby-on-rails

My array is
arr = ["wow what", "what anice", "anice day.currently", "day.currently i", "i am", "am in", "in delhi", "delhi but", "but in", "in night", "night i", "i am", "am going", "going to", "to us"]
arr.each do |el|
if !el.match('in') && !el.match('is').blank?
fresh_arr << el
end
but i have 110k element array and it give 8sec that,s too much time can i do this any another way
Thx

Use delete_if
arr.delete_if do |e|
e.match('in') && e.match('is').blank?
end
arr

Try this
arr.reject { |i| i.match('in') || i.match('is').blank? }

You can select all elements you need by doing this
arr.select{|el| !el.match('in') && !el.match('is').blank?}

Related

How do I search a Ruby hash from an array of values, and then return a hash based on the findings?

Here's an example hash and an example array to search in the hash:
nicknames = { "Black Mamba" => "Kobe Bryant",
"Half Man Half Amazing" => "Vince Carter",
"The Big Fundamental" => "Tim Duncan",
"Big Ticket" => "Kevin Garnett",
"Obi-Wan Ginobili" => "Manu Ginobili",
"The Answer" => "Allen Iverson" }
names = [ "Vince Carter", "Manu Ginobili", "Allen Iverson" ]
I want to return:
selected = { "Half Man Half Amazing" => "Vince Carter", "Obi-Wan Ginobili" => "Manu Ginobili", "The Answer" = "Allen Iverson" }
What's a good way to do this? Thanks!
You can simply do the following:
nicknames.select { |key, value| names.include?(value) }
(copy-paste the code you provided and mine in your IRB console and you'll see it working).
If the values in the hash are unique, then you can reverse the keys and the values. MrYoshiji's code works, but here is a more efficient way.
hash = nicknames.invert
names.to_enum.with_object({}){|k, h| h[hash[k]] = k}

Bringing values into a loop in Ruby

This is almost certainly a duplicate, but I can't find the original - I don't know the search terms to use. Which is why I'm on Stackoverflow instead of Google :)
Anyhow, here's my code:
def titleize(say)
index = 0
words = say.split
words.each do |word|
unless word == "and" || "or" || "over" || "the" || "for"
word.capitalize!
end
if index == 0
word.capitalize!
end
index += 1
end
say = words.join(" ")
end
Because index is declared before the loop, my if index == 0 is not working.
How do I let Ruby know about and use my object index? Also: what is this called?
Using index == 0 is perfectly fine as index is accessible within your loop. Your real problem is probably in this line:
word == "and" || "or" || "over" || "the" || "for"
This is always true-like! What you mean is:
["and", "or", "over", "the", "for"].include? word
Apart form that there is a method called each_with_index, which you can use like this:
words.each_with_index do |word, index|
I think you want to use with_index. Your word comparison was busted too.
def titleize(say)
words = say.split
l = ["and", "or", "over", "the", "for"]
words.each.with_index do |word, index|
word.capitalize! if index == 0 || !(l.include? word)
end
say = words.join(" ")
end
puts(titleize("hello there for you"))
puts(titleize("hi"))
puts(titleize("for"))
That's not how booleans work. The way this is evaluated is:
x == 'a' || 'b'
Becomes:
(x == 'a') || 'b'
Which is equivalent to:
'b'
What you're intending, translated to more idiomatic Ruby, is:
def titleize(say)
say.split.each_with_index do |word, index|
if (index == 0)
word.capitalize!
else
case (word)
when "a", "and", "or", "over", "the", "for"
# Leave lower-case
else
word.capitalize!
end
end
end.join(' ')
end
titleize('the time this is a test for the things!')
# => "The Time This Is a Test for the Things!"
I would do this it is more flexible and more ruby-esque
def titleize(sentence,exclusions=[])
sentence.split.map.with_index do |word,index|
(index == 0 || !exclusions.include?(word)) ? word.capitalize : word
end.join(' ')
end
For this case i used 'capitalize' without the bang in case any of the words are already capitalized.
"Hello".capitalize! #=> nil
"Hello".capitalize #=> "Hello"
It will also let you re-use the same list of exclusion or change them as you see fit
Call as
exclude = ["and", "or", "over", "the", "for"]
titleize("hello there you are over there", exclude)
#=> "Hello There You Are over There"
Your code returns the modification of say, but does change the contents of the variable. It appears that you want to modify the argument, but I'm not sure about that. I will first suggest a way to return the modified value of say (but not alter the value of say, and then will show how you could change the code to modify the argument.
Notice that I do not employ an index, and use a case statement to determine whether words after the first should be capitalized.
Code
def titleize(say)
words = say.split
return "" if words.empty?
words.first.capitalize!
return words.first if words.size == 1
words[1..-1].each do |word|
case word
when "and", "or", "over", "the", "for"
else
word.capitalize!
end
end
words.join(' ')
end
Examples
say = "and now is the time for all Rubyists to hunker down and code"
titleize(say)
#=> "And Now Is the Time for All Rubyists To Hunker Down and Code"
say
#=> "and now is the time for all Rubyists to hunker down and code"
say = " "
titleize(say)
#=> ""
say = " and "
titleize(say)
#=> "And"
Modifying the Argument
If you wish to modify the argument say, use String#replace:
def titleize_and_modify_arg(say)
words = say.split
str =
case words.size
when 0
""
when 1
words.first.capitalize
else
words.first.capitalize!
words[1..-1].each do |word|
case word
when "and", "or", "over", "the", "for"
else
word.capitalize!
end
end
words.join(' ')
end
say.replace(str)
end
say = "and now is the time for all Rubyists to hunker down and code"
titleize_and_modify_arg(say)
#=> "And Now Is the Time for All Rubyists To Hunker Down and Code"
say
#=> "And Now Is the Time for All Rubyists To Hunker Down and Code"
say = " and "
titleize_and_modify_arg(say)
#=> nil
say
#=> " and "
Notice that in the second example, titleize_and_modify_arg modifies say correctly, but returns nil. Of course, the method could be easily changed to return the value of say, as well as changing it, if that were desired.
Note also that, in the case statement, when words.siz => 1, it's capitalize, not capitalize!, as the latter would return nil if the word is already capitalized. capitalize! is need for the else case, however.
I recommend using each_index instead of each. See here.
Try this:
def titleize (say)
words = say.split
words.each_index do |index|
word = words[i]
unless word == "and" || "or" || "over" || "the" || "for"
word.capitalize!
end
if index == 0
word.capitalize!
end
end
say = words.join(" ")
end

How to parse values in multidimensional array and select one over the other based on condition?

I have an array that behaves like a multidimensional array through spaces, like:
"roles"=>["1 editor 0", "1 editor 1", "2 editor 0", "2 editor 1", "14 editor 0", "15 editor 0"], "commit"=>"Give Access", "id"=>"3"}
Each array value represents [category_id, user.title, checked_boolean], and comes from
form
<%= hidden_field_tag "roles[]", [c.id, "editor", 0] %>
<%= check_box_tag "roles[]", [c.id, "editor", 1 ], !!checked %>
which I process it using splits
params[:roles].each do |role|
cat_id = role[0].split(" ")[0]
title = role.split(" ")[1]
checked_boolean = role.split(" ")[2]
end
Given the array at the top, you can see that the "Category 1" & "Category 2" is checked, while "Cat 14" and "Cat 15" are not.
I would like to compare the values of the given array, and if both 1 & 0 exists for a given category_id, I would like to get rid of the value with "checked_boolean = 0". This way, if the boolean is a 1, I can check to see if the Role already exists, and if not, create it. And if it is 0, I can check to see if Role exists, and if it does, delete it.
How would I be able to do this? I thought of doing something like params[:roles].uniq but didn't know how to process the uniq only on the first split.
Or is there a better way of posting the "unchecks" in Rails? I've found solutions for processing the uncheck action for simple checkboxes that passes in either true/false, but my case is different because it needs to pass in true/false in addition to the User.Title
Let's params[:roles] is:
["1 editor 0", "1 editor 1", "2 editor 0", "2 editor 1", "14 editor 0", "15 editor 0"]
The example of the conversion and filtering is below:
roles = params[:roles].map {| role | role.split " " }
filtered = roles.select do| role |
next true if role[ 2 ].to_i == 1
count = roles.reduce( 0 ) {| count, r | r[ 0 ] == role[ 0 ] && count + 1 || count}
count == 1
end
# => [["1", "editor", "1"], ["2", "editor", "1"], ["14", "editor", "0"], ["15", "editor", "0"]]
filtered.map {| role | role.join( ' ' ) }
Since the select method returns a new filtered role array, so result array you can see above. But of course you can still use and source params[:roles], and intermediate (after map method worked) versions of role array.
Finally you can adduce the result array into the text form:
filtered.map {| role | role.join( ' ' ) }
=> ["1 editor 1", "2 editor 1", "14 editor 0", "15 editor 0"]
majioa's solution is certainly more terse and a better use of the language's features, but here is my take on it with a more language agnostic approach. I have only just started learning Ruby so I used this as an opportunity to learn, but it does solve your problem.
my_array = ["1 editor 0", "1 editor 0", "1 editor 1", "2 editor 0",
"2 editor 1", "14 editor 0", "15 editor 0"]
puts "My array before:"
puts my_array.inspect
# As we're nesting a loop inside another for each loop
# we can't delete from the same array without confusing the
# iterator of the outside loop. Instead we'll delete at the end.
role_to_del = Array.new
my_array.each do |role|
cat_id, checked_boolean = role.split(" ")[0], role.split(" ")[2]
if checked_boolean == "1"
# Search through the array and mark the roles for deletion if
# the category id's match and the found role's checked status
# doesn't equal 1.
my_array.each do |s_role|
s_cat_id = s_role.split(" ")[0]
if s_cat_id != cat_id
next
else
s_checked_boolean = s_role.split(" ")[2]
role_to_del.push s_role if s_checked_boolean != "1"
end
end
end
end
# Delete all redundant roles
role_to_del.each { |role| my_array.delete role }
puts "My array after:"
puts my_array.inspect
Output:
My array before:
["1 editor 0", "1 editor 0", "1 editor 1", "2 editor 0", "2 editor 1", "14 editor 0",
"15 editor 0"]
My array after:
["1 editor 1", "2 editor 1", "14 editor 0", "15 editor 0"]

Word Frequency count in a very inefficient way

This is my code for calculate word frequency
word_arr= ["I", "received", "this", "in", "email", "and", "found", "it", "a", "good", "read", "to", "share......", "Yes,", "Dr", "M.", "Bakri", "Musa", "seems", "to", "know", "what", "is", "happening", "in", "Malaysia.", "Some", "of", "you", "may", "know.", "He", "is", "a", "Malay", "extra horny", "horny nor", "nor their", "their babes", "babes are", "are extra", "extra SEXY..", "SEXY.. .", ". .", ". .It's", ".It's because", "because their", "their CONDOMS", "CONDOMS are", "are Made", "Made In", "In China........;)", "China........;) &&"]
arr_stop_kwd=["a","and"]
frequencies = Hash.new(0)
word_arr.each { |word|
if !arr_stop_kwd.include?(word.downcase) && !word.match('&&')
frequencies["#{word.downcase}"] += 1
end
}
when i have 100k data it will take 9.03 seconds,that,s to much time can i calculate any another way
Thx in advance
Take a look at Facets gem
You can do something like this using the frequency method
require 'facets'
frequencies = (word_arr-arr_stop_kwd).frequency
Note that stop word can be subtracted from the word_arr. Refer to Array Documentation.

Ruby delete_if multiple values - only first value being deleted

words.delete_if do |x|
x == ("a"||"for"||"to"||"and")
end
words is an array with many words. My code is deleting "a" but not deleting "for", "to" or "and".
May this will help you
words.delete_if do |x|
%w(a for to and).include?(x)
end
Just do
words - ["a", "for", "to", "and"]
Example
words = %w(this is a just test data for array - method and nothing)
=> ["this", "is", "a", "just", "test", "data", "for", "array", "-", "method", "and", "nothing"]
words = words - ["a", "for", "to", "and"]
=> ["this", "is", "just", "test", "data", "array", "-", "method", "nothing"]
If you run "a" || "b" in irb then you will always get "a" because it is a non null value and it would be returned by || always..
In your case "a"||"for" will always evaluate for "a" irrespective of the other values in the array..
So this is my alternate solution to your question
w = %W{a for to end}
words.reject! { |x| w.include?(x) }

Resources