Ruby delete_if multiple values - only first value being deleted - ruby-on-rails

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) }

Related

How to change hash key from array of hashes in ruby?

Given:
data = [
{"votable_id"=>1150, "user_ids"=>"1,2,3,4,5,6,"},
{"votable_id"=>1151, "user_ids"=>"55,66,34,23,56,7,8"}
]
This is the expected result. Array should have first 5 elements.
data = [
{"votable_id"=>1150, "user_ids"=>["1","2","3","4","5"]},
{"votable_id"=>1151, "user_ids"=>["55","66","34","23","56","7",8"]}
]
This is what I tried :
data.map{|x| x['user_ids'] = x['user_ids'].split(',').first(5)}
Any other optimized solution ?
You can also use .map and .tap like this
data.map do |h|
h.tap { |m_h| m_h["user_ids"]= m_h["user_ids"].split(',').first(5)}
end
data = [
{"votable_id"=>1150, "user_ids"=>"1,2,3,4,5,6,"},
{"votable_id"=>1151, "user_ids"=>"55,66,34,23,56,7,8"}
]
Code
h=data.map do |h|
h["user_ids"]=[h["user_ids"].split(',').first(5)].flatten
h
end
p h
Output
[{"votable_id"=>1150, "user_ids"=>["1", "2", "3", "4", "5"]}, {"votable_id"=>1151, "user_ids"=>["55", "66", "34", "23", "56"]}]
data.map { |h| h.merge("user_ids"=>h["user_ids"].split(',').first(5)) }
#=> [{"votable_id"=>1150, "user_ids"=>["1", "2", "3", "4", "5"]},
# {"votable_id"=>1151, "user_ids"=>["55", "66", "34", "23", "56"]}]
See Hash#merge. This leaves data unchanged. To modify (or mutate) data use Hash#merge! (aka update). h.merge(k=>v) is a shortcut for h.merge({ k=>v }).

Ruby find combination

I am trying to take input as a string.
Then I need to find all the possible combination and distinct combination but I am unable to do so.
input = "aabb"
Output I need to print all Combination =
'a','a','b','b','aa','ab','bb','aab','abb','aabb'
Now Distinct combination
'a','b','aa','ab','bb','aab','abb','aabb'
Then I need to count the letters and do a summation
'a','a','b','b','aa','ab','bb','aab','abb','aabb'
For this
result = 1+1+1+1+2+2+2+3+3+4
Similarly for the other combination I need to find summation.
You can use Array#combination.
To get all combinations:
input = "aabb"
res = []
input.size.times { |n| res << input.chars.combination(n+1).map { |a| a.join } }
res.flatten
#=> ["a", "a", "b", "b", "aa", "ab", "ab", "ab", "ab", "bb", "aab", "aab", "abb", "abb", "aabb"]
distinct combinations:
res.flatten.uniq
#=> ["a", "b", "aa", "ab", "bb", "aab", "abb", "aabb"]
to count the letters and do a summation:
res.flatten.uniq.map(&:size)
#=> [1, 1, 2, 2, 2, 3, 3, 4]
res.flatten.uniq.map(&:size).reduce(:+)
# => 18
To get all the substrings of your input (or more generally to get all subsequences of an Enumerable) you can use something like this:
def subsequences(e)
a = e.to_a
indices = (0..a.length - 1).to_a
indices.product(indices)
.reject { |i, j| i > j }
.map { |i, j| a[i..j] }
end
You would use that on your string like this: subsequences(input.chars).map(&:join). The chars and join are only necessary because Strings are not Enumerable, but the subsequences function does not really need that. You can just take out the first line and it should still work for strings (anything that has a "slicing" subscript operator, really ...).
Note also that this is not the only way to do this. The basic problem here is to iterate over all ordered pairs of indices of a sequence. You could also do that with basic loops. I just happen to find the cartesian product method very elegant. ;)
Once you have your first list in a variable, say list, the second task is as easy as list.uniq, and the third one is solved by
list.map(&:size).reduce(:+)

Mapping a table column with values that persist on create and update in Rails

I have a column in the table that has string values for:
arr = ["First Name", "Last Name", "location", "Description"]
I need to map each of these values to letters sequentially:
["A", "B", "C", "D"]
These letters aren't part of the table and aren't defined, but I am leaning toward creating a small hash with the above arr, unless there is a better suggestion?
I need to be able to map each letter to its correspond value in the arr, and when the arr is updated in a view, each letter should correspond in the arr. For example, if the "First Name" is removed from the arr, then the first latter should be "B", or if the "location" is removed, then the new array should be "A", "B", "D". Meaning, on create or update, letters should always be mapped to corresponding values in the arr. I hope I am making sense?
Many thanks.
For example you have
arr = ["First Name", "Last Name", "location", "Description"]
arr_hash= Hash.new
and yout have a instance for
#client =Client.first
hash[0] = []
hash[0] << arr
hash[1] = []
hash[1] << #client
and more....
You can make hash with pairs first, and then remove keys that are not present in updated array.
arr = ["First Name", "Last Name", "location", "Description"]
arr2 = ["A", "B", "C", "D"]
result = Hash[arr.zip(arr2)]
# => {"First Name"=>"A", "Last Name"=>"B", "location"=>"C", "Description"=>"D"}
# update original arr like:
arr = ["Last Name", "location", "Description"]
result.delete_if { |k, _| !arr.include?(k) }
# => {"Last Name"=>"B", "location"=>"C", "Description"=>"D"}

Is there a method in Ruby that divides an array into two smaller arrays based on a logical condition?

Let's say I have a list of elements in an array, but there is a logical way to divide them into two groups. I want to put those elements into two smaller arrays based on that criteria. Here is some code that works and helps illustrate what I mean:
foo = ['a', 'bb', 'c', 'ddd', 'ee', 'f']
=> ["a", "bb", "c", "ddd", "ee", "f"]
a = foo.select{|element| element.length == 1}
=> ["a", "c", "f"]
b = foo.reject{|element| element.length == 1}
=> ["bb", "ddd", "ee"]
I seem to remember seeing some way by which a single method call would assign both a and b, but I don't remember what it was. It would look something like
matching, non_matching = foo.mystery_method{|element| element.length == 1}
Am I crazy, or does such a method exist in Ruby and/or Rails?
Yes! http://ruby-doc.org/core-1.9.3/Enumerable.html#method-i-partition
matching, non_matching = foo.partition {|element| element.length == 1}

How can I order a list of letters ("a","b","c",...,"z","aa","ab")? String#succ and <=> don't seem to play well together in this case

One of my objects ('item') has an ID ('letter_id') in the format of "a", "b", ..., "aa", "ab", etc. To generate it I am using ruby's String#succ in an instance method like this:
def set_letter_id
last = parent.items.all(:order => "letter_id ASC").last
if last.nil?
self.letter_id = 'a'
else
self.letter_id = last.letter_id.succ
end
end
Now this works great until the 28th letter. The 27th will properly generate "aa", but then the value of last will always return the item with the letter_id of 'z' because the ordering of the returned items doesn't follow the same rules as String#succ.
I found this out from a comment over here - but now I'm struggling to find a nice solution around this issue. The problem is basically this:
"aa".succ #=> "ab" - great, that's what I want.
"z"<=>"aa" #=> 1 - not so great, "z" should actually be less than "aa"
Obviously this isn't necessarily a bug, but it makes sorting and ordering a list of letter_ids in this format quite difficult. Has anyone encountered this and found a workaround, or any suggestions that I might try? Thanks!
There was a solution in answers at link you've posted - you have to write own <=> in way to sort_by{|i|[i.length,i]}
irb> %w{a b c z aa ab zz aaa}.shuffle.sort_by { |i| [i.length,i] }
=> ["a", "b", "c", "z", "aa", "ab", "zz", "aaa"]
You can override the <=> method for your Item model to compare first by ID length, then by alphanumeric.
Something like this:
class Item < ActiveRecord::Base
# stuff
def <=>(other)
len_comp = self.letter_id.length <=> other.letter_id.length
return len_comp if len_comp != 0
self.letter_id <=> other.letter_id
end
end
That way you first compare for shorter ID length (i.e., "z" before "aa"), then lexicographically.
This sort of issue is exactly why some people discourage the use of String#succ. It clashes with Range, Object#to_a, and others.
Anyway, you probably know this, but things like this might help...
>> t
=> ["x", "y", "z", "aa", "ab", "ac", "ad", "ae", "af", "ag"]
>> t.shuffle.sort_by { |e| "%3s" % [e] }
=> ["x", "y", "z", "aa", "ab", "ac", "ad", "ae", "af", "ag"]
You could even renormalize this way and dispense with sort_by.

Resources