How to get array from string contained identical symbols in Ruby? - ruby

I have string like this: "1112222355". How can I get array like that ["111","2222","3","55"] using Ruby?

Assuming you want to group only consecutive elements, use Enumerable#chunk:
> "1112222355".chars.chunk { |x| x }.map { |c, cs| cs.join }
=> ["111", "2222", "3", "55"]

"1112222355".scan(/((.)\2*)/).map(&:first)
# => ["111", "2222", "3", "55"]

Related

Ruby Hash: type casting

I’m trying to get a better grasp on writing in Ruby and working with Hash tables and their values.
1. Say you have a hash:
‘FOO’= {‘baz’ => [1,2,3,4,5]}
Goal: convert each value into a string in the ‘Ruby’ way.
I’ve come across multiple examples of using .each eg.
FOO.each = { |k,v| FOO[k] = v.to_s }
However this renders an array encapsulated in a string. Eg. "[1,2,3,4,5]" where it should be ["1", "2", "3", "4", "5"].
2. When type casting is performed on a Hash that’s holds an array of values, is the result a new array? Or simply a change in type of value (eg. 1 becomes “1” when .to_s is applied (say the value was placed through a each enumerator like above).
An explanation is greatly appreciated. New to Ruby.
In the each block, k and v are the key value pair. In your case, 'baz' is key and [1,2,3,4,5] is value. Since you're doing v.to_s, it converts the whole array to string and not the individual values.
You can do something like this to achieve what you want.
foo = { 'baz' => [1,2,3,4,5] }
foo.each { |k, v| foo[k] = v.map(&:to_s) }
You can use Hash#transform_values:
foo = { 'baz' => [1, 2, 3, 4, 5] }
foo.transform_values { |v| v.map(&:to_s) } #=> {"baz"=>["1", "2", "3", "4", "5"]}

Find few adjacent identical numbers

Could you help me?
I need a regex that splits strings like
"11231114"
to
['11', '2', '3', '111', '4']
You could implement String#scan as follows:
"11231114".scan(/((\d)\2*)/).map(&:first)
#=> ["11", "2", "3", "111", "4"]
You could pass a block to String#scan pushing the match group to an array.
matches = []
"11231114".scan(/((\d)\2*)/) do |n,r| matches << n end
In Javascript you can do:
var m = "11231114".match(/(\d)\1*/g)
//=> ["11", "2", "3", "111", "4"]
You can use similar approach in whatever language/tool you're using.
Approach is to capture a digit using (\d) and then match all the back-references for the same using \1*.
You could do something like this,
> str = "11231114"
=> "11231114"
> str1 = str.gsub(/(?<=(\d))(?!\1)/, "*")
=> "11*2*3*111*4*"
> str1.split('*')
=> ["11", "2", "3", "111", "4"]
There is slice_when in Ruby 2.2:
"11231114".chars.slice_when { |x, y| x != y }.map(&:join)

add up values from 2 arrays based on duplicate values of the other one

A similar question has been answered here However I'd like to know how I can add up/group the numbers from one array based on the duplicate values of another array.
test_names = ["TEST1", "TEST1", "TEST2", "TEST3", "TEST2", "TEST4", "TEST4", "TEST4"]
numbers = ["5", "4", "3", "2", "9", "7", "6", "1"]
The ideal result I'd like to get is a hash or an array with:
{"TEST1" => 9, "TEST2" => 12, "TEST3" => 2, "TEST4" => 14}
Another way I found you can do:
test_names.zip(numbers).each_with_object(Hash.new(0)) {
|arr, hsh| hsh[arr[0]] += arr[1].to_i }
You can do it like this:
my_hash = Hash.new(0)
test_names.each_with_index {|name, index| my_hash[name] += numbers[index].to_i}
my_hash
#=> {"TEST1"=>9, "TEST2"=>12, "TEST3"=>2, "TEST4"=>14}
I wish to follow #squidguy's example and use Enumerable#zip, but with a different twist:
{}.tap { |h| test_names.zip(numbers.map(&:to_i)) { |a|
h.update([a].to_h) { |_,o,n| o+n } } }
#=> {"TEST1"=>9, "TEST2"=>12, "TEST3"=>2, "TEST4"=>14}
Object#tap is here just a substitute for Enumerable#each_with_object or for having h={} initially and a last line with just h.
I'm using the form of Hash#update (aka merge!) that takes a block for determining the merged value for each key that is present in both the original hash (h) and the hash being merged ([a].to_h). There are three block variables, the shared key (which we don't use here, so I've replaced it with the placeholder _), and the values for that key for the original hash (o) and for the hash being merged (n).

How to join second or third dimension array items without affecting first dimension

I am trying to create an array that shows every digit permutation of a given number input. With a given input "123", the array should look like this:
["123", "132", "213", "231", "312", "321"]
I can get an array containing arrays of the separate digits:
a = []
"123".split('').each {|n| a.push(n) }
arraycombinations = a.permutation(a.length).to_a
# => [["1", "2", "3"], ["1", "3", "2"], ["2", "1", "3"], ["2", "3", "1"], ["3", "1", "2"], ["3", "2", "1"]]
but I cannot figure out how to join the second or third dimensions of arraycombinations while preserving the first dimension.
Each of these attempts failed:
arraycombinations.map {|x| print arraycombinations.join("") }
arraycombinations.map {|ar| ar.split(",") }
arraycombinations.each {|index| arraycombinations(index).join("") }
How can I isolate the join function to apply to only the second dimension within a multidimensional array?
Assuming you already have an array of arrays such as
a = [["1","2","3"],["1","3","2"],["2","1","3"],["2","3","1"], ["3","1","2"],["3","2","1"]]
a.map { |i| i.join}
#=>["123", "132", "213", "231", "312", "321"]
It's simple really
"123".split("").permutation.to_a.map { |x| x.join }
Let me explain a bit:
"123".split("") gives you an array ["1","2","3"]
permutation.to_a gives you array of arrays [["1","2","3"], ["2","1","3"] ... ]
then you must join each of those arrays inside with map { |x| x.join }
and you get the required end result.
Like this:
arraycombinations.map(&:join)
# => ["123", "132", "213", "231", "312", "321"]

Creating a hash from two arrays with identical values in Ruby

I'm having issues creating a hash from 2 arrays when values are identical in one of the arrays.
e.g.
names = ["test1", "test2"]
numbers = ["1", "2"]
Hash[names.zip(numbers)]
works perfectly it gives me exactly what I need => {"test1"=>"1", "test2"=>"2"}
However if the values in "names" are identical then it doesn't work correctly
names = ["test1", "test1"]
numbers = ["1", "2"]
Hash[names.zip(numbers)]
shows {"test1"=>"2"} however I expect the result to be {"test1"=>"1", "test1"=>"2"}
Any help is appreciated
Hashes can't have duplicate keys. Ever.
If they were permitted, how would you access "2"? If you write myhash["test1"], which value would you expect?
Rather, if you expect to have several values under one key, make a hash of arrays.
names = ["test1", "test1", "test2"]
numbers = ["1", "2", "3"]
Hash.new.tap { |h| names.zip(numbers).each { |k, v| (h[k] ||= []) << v } }
# => {"test1"=>["1", "2"], "test2"=>["3"]}

Resources