I have an array with Product Ids and Color HEX Codes
Input:
#campaign.selectedproducts
Output:
["2,333333","1,333333",4,444444"]
I'm trying to make a new array with all of the product data by finding it with id:
#selectedgifts = #campaign.selectedproducts.collect [{|i| Product.find(i) }, |i| i.split(',').last]
Array should output
["Product Object, HEX code", "Product Object, HEX code"]
¿Any help?
Thanks!
You can try with group_by method like below:
#campaign.selectedproducts.group_by(&:color_code).transform_values{|val| val.pluck(:id).uniq}
Converting Product object to string is not what you want i guess. So i suggest you storing each element as hash instead of string.
#campaign.selectedproducts.map do |string|
id, hex_code = string.split(',')
product = Product.find(id)
{ product => hex_code }
end
Edit: Or you can store each element as array like this:
#campaign.selectedproducts.map do |string|
id, hex_code = string.split(',')
product = Product.find(id)
[product, hex_code]
end
In an API processing a large number of attributes, the following pattern is frequent
if !article[:ingredients].nil?
clean_ingredients = article[:ingredients].tr('*$+!##Â', ' ')
ingredients = clean_ingredients.downcase.capitalize
else
ingredients = nil
end
for a JSON string as: { "id": "YYYYYY", "article": [ { "ingredients": "long string", [...]
Unfortunately, a method defined as
def empty_and_clean(array_element, element_attribute)
if !array_element[:element_attribute].nil?
clean_ingredients = array_element[:element_attribute].tr('*$+!##Â', ' ')
ingredients = clean_ingredients.downcase.capitalize
else
ingredients = nil
end
end
cannot be called in the method as empty_and_clean(article, ingredients) as it returns
undefined local variable or method 'ingredients'
What syntax allows to refactor this pattern?
You can call your empty_and_clean method this way:
empty_and_clean(article, :ingredients)
Just modify empty_and_clean to use element_attribute directly rather than the symbol :element_attribute.
I suggest you read more about symbols in Ruby to understand how this works.
Also, array_element is a misleading name because it is an array, not an element of an array. array would be slightly better, but is still too generic. Maybe objects or something else that describes what is actually in the array.
I have:
s = "like_so__case"
camelize gives this:
s.camelize # => "LikeSoCase"
I'm looking for conversion up to a double underscore __ to get:
"LikeSo__case"
How can I camelize only up to a certain part of a string?
The simplest option is to gsub part of your string.
'like_so__case'.gsub(/(.*?)(__.*)/) { "#{$1.camelize}#{$2}" }
#=> "LikeSo__case"
UPDATE
Cleaner and faster way arising from comments.
'like_so__case__h'.sub(/(.*?)(?=__)/, &:camelize)
#=> "LikeSo__case__h"
s = "like_so__case"
=> "like_so__case"
s.split('__', 2).tap { |s| s[0] = s[0].camelize }.join('__')
=> "LikeSo__case"
You of course could wrap it in string method
For getting this LikeSo__case, we can do like:
s="like_so__case"
s.split('__').tap { |s| s[0] = s[0].camelize }.join('__')
Your description on the demand is not so clear.
From your excepted result, I understand it as 'camelize a part of string until a pattern'. I should note one thing first that camelize is not part of Ruby's standard library of class String. ActiveSupport::Inflector provides it.
So if you want to just camelize each part divided by a pattern, use str.split('_').map(&:capitalize).join('_'). In your case, it returns 'Like_So__Case'.
Ruby's String has another instance method named partition, which splits the string into three parts (an array):
Part before the pattern
The pattern
Part after the pattern
So str.partition('__').tap { |a| a[0] = a[0].split('_').map(&:capitalize).join }.join should be your answer in plain Ruby.
No need of relying on camelize. Simply, this:
"like_so__case"
.gsub(/_?([a-z])([a-z]*)(?=.*__)/i){$1.upcase + $2.downcase}
# => "LikeSo__case"
def camelize(s)
for i in 0..s.size-2 do
if s[i] == "_" and s[i+1] == "_"
next
elsif s[i] == "_" and s[i+1] != "_" and s[i-1] != "_"
s[i+1] = s[i+1].upcase
s[i] = ""
else
next
end
end
return s
end
Use this method to solve your problem
s = "like_so__case"
i = s.index('__')
#=> 7
s.tap { |s| s[0,i] = s[0,i].camelize }
#=> LikeSo__case
The last line could be replaced by two lines:
s[0,i] = s[0,i].camelize
s
If the original string is not to be mutated write
s.dup.tap { |s| s[0,i] = s[0,i].camelize }
String = "Mod1:10022932,10828075,5946410,13321905,5491120,5030731|Mod2:22704455,22991440,22991464,21984312,21777721,21777723,21889761,21939852,23091478,22339903,23091485,22099714,21998260,22364832,21939858,21944274,21944226,22800221,22704443,21777728,21777719,21678184,21998265,21834900,21984331,22704454,21998261,21944214,21862610,21836482|Mod3:10828075,13321905,5491120,5946410,5030731,15806212,4100566,4787137,2625339,2408317,2646868,19612047,2646862,11983534,8591489,19612048,10249319,14220471,15806209,13330887,15075124,17656842,3056657,5086273|Mod4:10828075,5946410,13321905,5030731,5491120,4787137,4100566,15806212,2625339,3542205,2408317,2646862,2646868|Mod5:10022932;0.2512,10828075;0.2093,5030731;0.1465,5946410;0.1465,4787137;0.1465,2625339;0.0143,5491120;0.0143,13321905;0.0143,3542205;0.0143,15806212;0.0119,4100566;0.0119,19612047;0.0100,2408317;0.0100"
How can I split it out so that I can get each title(Mod1, Mod2..) and the ID's that belong to each title.
This is that I've tried so far, which is removing everything after the pipe, which I dont want.
mod_name = string.split(":")[0]
mod_ids = string.split(":")[1] #This gets me the ID's but also include the |Mod*
ids = mod_mod_ids.split("|").first.strip #Only returns Id's before the first "|"
Desired Output:
I need to save mod_name and mod_ids to their respective columns,
mod_name = #name ("Mod1...Mod2 etc) #string
mod_ids = #ids (All Ids after the ":" in Mod*:) #array
I think this does what you want:
ids = string.split("|").map {|part| [part.split(":")[0], part.split(":")[1].split(/,|;/)]}
There are a couple of ways to do this:
# This will split the string on "|" and ":" and will return:
# %w( Mod1 id1 Mod2 id2 Mod3 id3 ... )
ids = string.split(/[|:]/)
# This will first split on "|", and for each string, split it again on ":" and returs:
# [ %w(Mod1 id1), %w(Mod2 id2), %w(Mod3 id3), ... ]
ids = string.split("|").map { |str| str.split(":") }
If you want a Hash as a result for easy access via the titles, then you could do this:
str.split('|').inject({}){|h,x| k,v = x.split(':'); h[k] = v.split(','); h}
=> {
"Mod1"=>["10022932", "10828075", "5946410", "13321905", "5491120", "5030731"],
"Mod2"=>["22704455", "22991440", "22991464", "21984312", "21777721", "21777723", "21889761", "21939852", "23091478", "22339903", "23091485", "22099714", "21998260", "22364832", "21939858", "21944274", "21944226", "22800221", "22704443", "21777728", "21777719", "21678184", "21998265", "21834900", "21984331", "22704454", "21998261", "21944214", "21862610", "21836482"],
"Mod3"=>["10828075", "13321905", "5491120", "5946410", "5030731", "15806212", "4100566", "4787137", "2625339", "2408317", "2646868", "19612047", "2646862", "11983534", "8591489", "19612048", "10249319", "14220471", "15806209", "13330887", "15075124", "17656842", "3056657", "5086273"],
"Mod4"=>["10828075", "5946410", "13321905", "5030731", "5491120", "4787137", "4100566", "15806212", "2625339", "3542205", "2408317", "2646862", "2646868"],
"Mod5"=>["10022932;0.2512", "10828075;0.2093", "5030731;0.1465", "5946410;0.1465", "4787137;0.1465", "2625339;0.0143", "5491120;0.0143", "13321905;0.0143", "3542205;0.0143", "15806212;0.0119", "4100566;0.0119", "19612047;0.0100", "2408317;0.0100"]
}
Untested:
all_mods = {}
string.split("|").each do |fragment|
mod_fragments = fragment.split(":")
all_mods[mod_fragments[0]] = mod_fragments[1].split(",")
end
What I ended up using thanks to #tillerjs help.
data = sting.split("|")
data.each do |mod|
module_name = mod.split(":")[0]
recommendations = mod.split(":")[1]
end