Split a string into an array of numbers - ruby-on-rails

My string:
>> pp params[:value]
"07016,07023,07027,07033,07036,07060,07062,07063,07065,07066,07076,07081,07083,07088,07090,07092,07201,07202,07203,07204,07205,07206,07208,07901,07922,07974,08812,07061,07091,07207,07902"
How can this become an array of separate numbers like :
["07016", "07023", "07033" ... ]

result = params[:value].split(/,/)
String#split is what you need

Try this:
arr = "07016,07023,07027".split(",")

Note that what you ask for is not an array of separate numbers, but an array of strings that look like numbers. As noted by others, you can get that with:
arr = params[:value].split(',')
# Alternatively, assuming integers only
arr = params[:value].scan(/\d+/)
If you actually wanted an array of numbers (Integers), you could do it like so:
arr = params[:value].split(',').map{ |s| s.to_i }
# Or, for Ruby 1.8.7+
arr = params[:value].split(',').map(&:to_i)
# Silly alternative
arr = []; params[:value].scan(/\d+/){ |s| arr << s.to_i }

Related

How to find the max value in an array of hashes?

Given this array of hashes here:
arr = [{:question_type=>"Fire", :total=>0.0}, {:question_type=>"Water", :total=>0.0}, {:question_type=>"Metal", :total=>0.0}, {:question_type=>"Earth", :total=>0.0}, {:question_type=>"Wood", :total=>100.0}]
I would like to pick the hash with the highest value for the total key.
So the code bellow seems to do the work
max = arr.max_by{|x| x[:total]}
puts max[:question_type]
#=> Wood
However if I have 2 hashes with the same value it will return the first one only
arr2 = [{:question_type=>"Fire", :total=>0.0}, {:question_type=>"Water", :total=>0.0}, {:question_type=>"Metal", :total=>0.0}, {:question_type=>"Earth", :total=>50.0}, {:question_type=>"Wood", :total=>50.0}]
max = arr2.max_by{|x| x[:total]} #it should be arr2
puts max[:question_type]
#=> Earth
What would be the best way to get it to return Earth and Wood in case both are the highest values?
You can do this with group_by and max:
arr.group_by { |x| x[:total] }.max.last
You could do this in tow steps this way:
max = arr.max_by{|x| x[:total]}
max = arr.select{ |x| x[:total] == max[:total }
You can always just take that max value and select.
arr = [{:question_type=>"Fire", :total=>0.0}, {:question_type=>"Water", :total=>0.0}, {:question_type=>"Metal", :total=>0.0}, {:question_type=>"Earth", :total=>50.0}, {:question_type=>"Wood", :total=>50.0}]
max = arr.max_by{|x| x[:total]}
max_values = arr.select{|hash| hash[:total] == max[:total]}
An alternative approach to some solid answers already posted here is to roll your own method to retrieve the max values, including multiples if there are ties:
def get_max(arr)
result = []
current_max = 0.0
arr.each do |hash|
if hash[:total] > current_max
result = [hash[:question_type]]
current_max = hash[:total]
elsif hash[:total] == current_max
result.push(hash[:question_type])
end
end
result
end
arr = [{:question_type=>"Fire", :total=>0.0}, {:question_type=>"Water", :total=>0.0}, {:question_type=>"Metal", :total=>0.0}, {:question_type=>"Earth", :total=>50.0}, {:question_type=>"Wood", :total=>50.0}]
puts get_max(arr)
# => ["Earth", "Wood"]
It may not be as succinct as using something like #max_by and #select, but the benefit of the above approach is you only iterate through the array once.
Hope it helps!

push to string and separate values

I have arr = [1,2,3,4,5..etc]
str = ''
arr.each do|a|
str << a
end
I need str='1,2,3..etc'
Instead of str='123'
in short I need add separator between values
You should use Array#join method.
arr = [1,2,3,4,5..9]
arr.join(',')

Write bunch of hashes to a json file

Whats the right approach to write number of hashesh to a json file that can be parsed effeciently later on.
e.g:
hash1 = {:a=>1,:b=>'foo'}
hash2 = {:c=>3,:b=>'bar'}
...
hashN = {...}
File.open("data.json", "a") { |io| io.write(hash1.to_json)}
I can write a comma after each hash to the file, but this is not looking nice to me.. is it a better way to do it?
that can be parsed effeciently later on.
You will want to put your hashes in a list so that later you can load and parse everything in one sweep:
require 'json'
arr = []
arr << {:a=>1,:b=>'foo'}
arr << {:c=>3,:b=>'bar'}
json_str = arr.to_json
File.open("yourfile", 'w') { |file| file.write(json_str) }
Later on to load:
contents = File.read('yourfile')
arr = JSON.parse(contents)

Ruby split string

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

Ruby way to group anagrams in string array

I implemented a function to group anagrams.
In a nutshell:
input: ['cars', 'for', 'potatoes', 'racs', 'four','scar', 'creams', scream']
output: [["cars", "racs", "scar"], ["four"], ["for"], ["potatoes"],["creams", "scream"]]
I would like to know if there is a better way to do this.
I really think I used too much repetition statements: until, select,
delete_if.
Is there any way to combine the select and delete_if statement? That
means, can selected items be automatically deleted?
Code:
def group_anagrams(words)
array = []
until words.empty?
word = words.first
array.push( words.select { |match| word.downcase.chars.sort.join.eql?(match.downcase.chars.sort.join ) } )
words.delete_if { |match| word.downcase.chars.sort.join.eql?(match.downcase.chars.sort.join ) }
end
array
end
Thanks in advance,
Like that:
a = ['cars', 'for', 'potatoes', 'racs', 'four','scar', 'creams', 'scream']
a.group_by { |element| element.downcase.chars.sort }.values
Output is:
[["cars", "racs", "scar"], ["for"], ["potatoes"], ["four"], ["creams", "scream"]]
If you want to you can turn this one-liner to a method of course.
You could use the partition function instead of select, implemented in Enumerable. It splits the entries within the array according to the decision-function into two arrays.
def group_anagrams(words)
array = []
until words.empty?
word = words.first
delta, words = words.partition { |match| word.downcase.chars.sort.join.eql?(match.downcase.chars.sort.join ) } )
array += delta
end
array
end
(untested)

Resources