Find few adjacent identical numbers - ruby

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)

Related

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"]

Make two dimensional array

My array is ["Mehmet,1,3,0,0,0\n", "Veli,2,1,2,0,2\n", "Ali,0,1,1,0,0\n"].
I want to declare two dimensional array like array[1][2] with first dimension for name and second one for note.
How can I make it?
Text.txt is
Mehmet,1,3,0,0,0
Veli,2,1,2,0,2
Ali,0,1,1,0,0
My code is
filename = "text.txt"
results = []
File.new(filename, "r").each { |line| results << line }
results.inject([]){|ar,s|
ar.concat(s.split(/,/))}
puts results.inspect
To modify the set that you first posted:
data = ["Mehmet,1,3,0,0,0\n", "Veli,2,1,2,0,2\n", "Ali,0,1,1,0,0\n"]
data = data.map {|x| y = x.split(","); [y.delete_at(0), y] }
=> [["Mehmet", ["1", "3", "0", "0", "0\n"]],
["Veli", ["2", "1", "2", "0", "2\n"]],
["Ali", ["0", "1", "1", "0", "0\n"]]]
puts data[0][0]
=> Mehmet
array = File.read("text.txt").split
# => ["Mehmet,1,3,0,0,0", "Veli,2,1,2,0,2", "Ali,0,1,1,0,0"]
array.map { |ar| x, *xs = ar.split(","); [x, xs.join] }
# => [["Mehmet", "13000"], ["Veli", "21202"], ["Ali", "01100"]]
Or, if you don't want to join the second sub-array
array.map { |ar| x, *xs = ar.split(","); [x, xs] }
# => [["Mehmet", ["1", "3", "0", "0", "0"]],
# ["Veli", ["2", "1", "2", "0", "2"]],
# ["Ali", ["0", "1", "1", "0", "0"]]]
2d array means array of arrays. So, simply it can be like:
board = [ [ 1, 2, 3 ],[ 4, 5, 6 ]]
Are you looking for something like this?
array = ["Mehmet,1,3,0,0,0\n", "Veli,2,1,2,0,2\n", "Ali,0,1,1,0,0\n"]
new_array = array.map do |elem|
splited = elem.split(/[,\s]/)
[splited.shift, splited]
end
# => [["Mehmet", ["1", "3", "0", "0", "0"]],
# ["Veli", ["2", "1", "2", "0", "2"]],
# ["Ali", ["0", "1", "1", "0", "0"]]]

How to get array from string contained identical symbols in 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"]

How to combination/permutation in ruby?

I've this familiar question that looks like permutation/combination of the Math world.
How can I achieve the following via ruby?
badges = "1-2-3"
badge_cascade = []
badges.split("-").each do |b|
badge_cascade << b
end
Gives: => ["1", "2", "3"]
But I want it to be is:
=> ["1", "2", "3",
"1-2", "2-3", "3-1", "2-1", "3-2", "1-3",
"1-2-3", "2-3-1", "3-1-2"]
Functional approach:
bs = "1-2-3".split("-")
strings = 1.upto(bs.size).flat_map do |n|
bs.permutation(n).map { |vs| vs.join("-") }
end
#=> ["1", "2", "3", "1-2", "1-3", "2-1", "2-3", "3-1", "3-2", "1-2-3", "1-3-2", "2-1-3", "2-3-1", "3-1-2", "3-2-1"]
You ned to use Array#permutation method in order to get all permutations:
arr = "1-2-3".split '-' # => ["1", "2", "3"]
res = (1..arr.length).reduce([]) { |res, length|
res += arr.permutation(length).to_a
}.map {|arr| arr.join('-')}
puts res.inspect
# => ["1", "2", "3", "1-2", "1-3", "2-1", "2-3", "3-1", "3-2", "1-2-3", "1-3-2", "2-1-3", "2-3-1", "3-1-2", "3-2-1"]
Let me explain the code:
You split string into array passing separator '-' to String#split method
You need all permutations of length 1, 2, 3. Range 1..arr.length represents all these lengths.
You collect an array of all permutations using Enumerable#reduce.
You will get array of arrays here:
[["1"], ["2"], ["3"], ["1", "2"], ["1", "3"], ["2", "1"], ["2", "3"], ["3", "1"], ["3", "2"], ["1", "2", "3"], ["1", "3", "2"], ["2", "1", "3"], ["2", "3", "1"], ["3", "1", "2"], ["3", "2", "1"]]
You transform all subarrays of this array into strings using Array#join with your '-' separator inside of Enumerable#map
Array#permutation(n) will give you all the permutations of length n as an Array of Arrays so you can call this with each length between 1 and the number of digits in badges. The final step is to map these all back into strings delimited with -.
badges = "1-2-3"
badges_split = badges.split('-')
permutations = []
(1..badges_split.size).each do |n|
permutations += badges_split.permutation(n).to_a
end
result = permutations.map { |permutation| permutation.join('-') }
Update: I think Alex's use of reduce is a more elegant approach but I'll leave this answer here for now in case it is useful.

Resources