Related
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 2 years ago.
Improve this question
A String s comprised of numbers from 0-9 contains a perfect substring if all the elements within a substring occurs exactly k times. Calculate the number of perfect substrings in s.
EXAMPLE
s = '1102021222'
k = 2
Here s contains 6 substrings:
11
0202
110202
102021
22
22
Can anyone help me with the solution to this in Ruby with the least complexity?
TIA..
Code
def count_em(str, k)
enum = str.each_char
(k..str.size).step(k).sum do |n|
enum.each_cons(n).count do |a|
a.tally.all? { |_k,v| v == k }
end
end
end
Examples
str = '1102021222'
count_em(str, 1) #=> 18 ( 1, 1, 0, 2, 0, 2, 1, 2, 2, 2,
# 10, 02, 20, 02, 21, 12, 102, 021
count_em(str, 2) #=> 6 (11, 22, 22, 0202, 110202, 102021)
count_em(str, 3) #=> 1 (102021)
count_em(str, n) #=> 0 for n > 3
Explanation
Enumerable#tally made its debut in Ruby v2.7. To support earlier versions of Ruby replace tally with
each_with_object(Hash.new(0)) { |n,h| h[n] += 1 }
Enumerable#sum was new in Ruby 2.4. To support earlier versions of Ruby replace sum with
reduce(:+)
See also Enumerable#each_cons, Enumerable#count and Enumerable#all? and Hash::new.
Note that no strings having k instances of all unique digits contained in the string could be produced for values of n that are not multiples of k. It is for that reason that step(k) is present.
The easiest way to explain the calculations is to salt the method with puts statements and run it.
def count_em(str, k)
puts "k = #{k}"
enum0 = str.each_char
puts "enum0 = #{enum0}"
(k..str.size).step(k).sum do |n|
puts "n = #{n}"
enum1 = enum0.each_cons(n)
puts " enum1.to_a = #{enum1.to_a}"
enum1.count do |a|
puts " a = #{a}"
h = a.tally
puts " a.tally = #{h}"
puts " a.tally.all? {|_k,v| v == k} = #{h.all? {|_k,v| v==k}}"
h.all? { |_k,v| v==k }
end
end
end
The line puts " enum1.to_a = #{enum1.to_a}" merely displays the values that will be generated by the enumerator enum1 and passed to count's block.
Try it for k = 2:
count_em(str, 2)
#=> 6
displays the following:
k = 2
enum0 = #<Enumerator:0x00007f9467ab60f0>
n = 2
enum1.to_a = [["1", "1"], ["1", "0"], ["0", "2"], ["2", "0"],
["0", "2"], ["2", "1"], ["1", "2"], ["2", "2"],
["2", "2"]]
a = ["1", "1"]
a.tally = {"1"=>2}
a.tally.all? {|_k,v| v == k} = true
a = ["1", "0"]
a.tally = {"1"=>1, "0"=>1}
a.tally.all? {|_k,v| v == k} = false
a = ["0", "2"]
a.tally = {"0"=>1, "2"=>1}
a.tally.all? {|_k,v| v == k} = false
a = ["2", "0"]
a.tally = {"2"=>1, "0"=>1}
a.tally.all? {|_k,v| v == k} = false
a = ["0", "2"]
a.tally = {"0"=>1, "2"=>1}
a.tally.all? {|_k,v| v == k} = false
a = ["2", "1"]
a.tally = {"2"=>1, "1"=>1}
a.tally.all? {|_k,v| v == k} = false
a = ["1", "2"]
a.tally = {"1"=>1, "2"=>1}
a.tally.all? {|_k,v| v == k} = false
a = ["2", "2"]
a.tally = {"2"=>2}
a.tally.all? {|_k,v| v == k} = true
a = ["2", "2"]
a.tally = {"2"=>2}
a.tally.all? {|_k,v| v == k} = true
n = 4
enum1.to_a = [["1", "1", "0", "2"], ["1", "0", "2", "0"],
["0", "2", "0", "2"], ["2", "0", "2", "1"],
["0", "2", "1", "2"], ["2", "1", "2", "2"],
["1", "2", "2", "2"]]
a = ["1", "1", "0", "2"]
a.tally = {"1"=>2, "0"=>1, "2"=>1}
a.tally.all? {|_k,v| v == k} = false
a = ["1", "0", "2", "0"]
a.tally = {"1"=>1, "0"=>2, "2"=>1}
a.tally.all? {|_k,v| v == k} = false
a = ["0", "2", "0", "2"]
a.tally = {"0"=>2, "2"=>2}
a.tally.all? {|_k,v| v == k} = true
a = ["2", "0", "2", "1"]
a.tally = {"2"=>2, "0"=>1, "1"=>1}
a.tally.all? {|_k,v| v == k} = false
a = ["0", "2", "1", "2"]
a.tally = {"0"=>1, "2"=>2, "1"=>1}
a.tally.all? {|_k,v| v == k} = false
a = ["2", "1", "2", "2"]
a.tally = {"2"=>3, "1"=>1}
a.tally.all? {|_k,v| v == k} = false
a = ["1", "2", "2", "2"]
a.tally = {"1"=>1, "2"=>3}
a.tally.all? {|_k,v| v == k} = false
n = 6
enum1.to_a = [["1", "1", "0", "2", "0", "2"], ["1", "0", "2", "0", "2", "1"],
["0", "2", "0", "2", "1", "2"], ["2", "0", "2", "1", "2", "2"],
["0", "2", "1", "2", "2", "2"]]
a = ["1", "1", "0", "2", "0", "2"]
a.tally = {"1"=>2, "0"=>2, "2"=>2}
a.tally.all? {|_k,v| v == k} = true
a = ["1", "0", "2", "0", "2", "1"]
a.tally = {"1"=>2, "0"=>2, "2"=>2}
a.tally.all? {|_k,v| v == k} = true
a = ["0", "2", "0", "2", "1", "2"]
a.tally = {"0"=>2, "2"=>3, "1"=>1}
a.tally.all? {|_k,v| v == k} = false
a = ["2", "0", "2", "1", "2", "2"]
a.tally = {"2"=>4, "0"=>1, "1"=>1}
a.tally.all? {|_k,v| v == k} = false
a = ["0", "2", "1", "2", "2", "2"]
a.tally = {"0"=>1, "2"=>4, "1"=>1}
a.tally.all? {|_k,v| v == k} = false
n = 8
enum1.to_a = [["1", "1", "0", "2", "0", "2", "1", "2"],
["1", "0", "2", "0", "2", "1", "2", "2"],
["0", "2", "0", "2", "1", "2", "2", "2"]]
a = ["1", "1", "0", "2", "0", "2", "1", "2"]
a.tally = {"1"=>3, "0"=>2, "2"=>3}
a.tally.all? {|_k,v| v == k} = false
a = ["1", "0", "2", "0", "2", "1", "2", "2"]
a.tally = {"1"=>2, "0"=>2, "2"=>4}
a.tally.all? {|_k,v| v == k} = false
a = ["0", "2", "0", "2", "1", "2", "2", "2"]
a.tally = {"0"=>2, "2"=>5, "1"=>1}
a.tally.all? {|_k,v| v == k} = false
n = 10
enum1.to_a = [["1", "1", "0", "2", "0", "2", "1", "2", "2", "2"]]
a = ["1", "1", "0", "2", "0", "2", "1", "2", "2", "2"]
a.tally = {"1"=>3, "0"=>2, "2"=>5}
a.tally.all? {|_k,v| v == k} = false
Given the expression
1 * 2 / 3 + 4
I'm trying to write out all possible variants of the equation when implementing order of operations. Such as:
(1 * 2) / 3) + 4
and
(1 * (2 / 3)) + 4
This is what I have now:
expression = [1.0, "+", 2.0, "+", 3.0, "+", 4.0]
storage = []
exp1 = expression #Make new object because insert method will overwrite expression object
storage << exp1.insert(0, "((").insert(4, ")").insert(7, ")")
But exp1's changes reflect in expression as well. I even made them in separate methods but the changes keep reflecting on expression.
How do I keep the expression object unchanged? I need to configure the original expression 5 times in total, but I'm struggling to keep it clean when I use insert. Reading the Ruby docs, the insert method is the only one suitable to what I'm doing.
Do I have to use a different data structure to store 1 * 2 / 3 + 4 other than an array?
Consider using #dup so that you don't alter the original set:
expression.dup.insert(0, "((").insert(4, ")").insert(7, ")")
Code
def all_equations(expression)
nums = expression.select { |o| o.kind_of? Numeric }.map(&:to_s)
ops = expression.select { |o| o.is_a? String }.uniq
ops.permutation(ops.size).to_a.map { |ao|
([nums.first] + ao.zip(nums[1..-1]).map(&:join)).join }
end
Examples
all_equations [1.0, "*", 2.0, "/", 3.0, "+", 4.0]
#=> ["1.0*2.0/3.0+4.0", "1.0*2.0+3.0/4.0", "1.0/2.0*3.0+4.0",
# "1.0/2.0+3.0*4.0", "1.0+2.0*3.0/4.0", "1.0+2.0/3.0*4.0"]
a = all_equations [1.0, "*", 2.0, "/", 3.0, "+", 4.0, "-", 4.0, "**", 5.0]
#=> ["1.0*2.0/3.0+4.0-4.0**5.0", "1.0*2.0/3.0+4.0**4.0-5.0",
# ...
# "1.0*2.0+3.0**4.0/4.0-5.0", "1.0*2.0+3.0**4.0-4.0/5.0",
# ...
# "1.0**2.0-3.0+4.0*4.0/5.0", "1.0**2.0-3.0+4.0/4.0*5.0"]
a.size
#=> 120
Explanation
The steps are as follows.
expression = [1.0, "*", 2.0, "/", 3.0, "*", 3.0] # note `"*"` appears twice
nums = expression.select { |o| o.kind_of? Numeric }.map(&:to_s)
#=> ["1.0", "2.0", "3.0", "3.0"]
ops = expression.select { |o| o.is_a? String }
#=> ["*", "/", "*"]
a = ops.uniq
#=> ["*", "/"]
b = a.permutation(a.size)
#=> #<Enumerator: ["*", "/"]:permutation(2)>
c = b.to_a
#=> [["*", "/"], ["/", "*"]]
c.map { |ao| ([nums.first] + ao.zip(nums[1..-1]).map(&:join)).join }
#=> ["1.0*2.0/3.0", "1.0/2.0*3.0"]
uniq has effect only when ops contains duplicates.
Extension
The following permits the numbers to be reordered as well. (I initially thought this was a requirement, which is the only reason I am offering this modification.)
expression = [1.0, "*", 2.0, "/", 3.0, "+", 4.0]
nums = expression.select { |o| o.kind_of? Numeric }.map(&:to_s)
#=> ["1.0", "2.0", "3.0", "4.0"]
ops = expression.select { |o| o.is_a? String }
#=> [["*", "/", "+"], ["*", "+", "/"], ["/", "*", "+"],
# ["/", "+", "*"], ["+", "*", "/"], ["+", "/", "*"]]
anums, aops = nums.permutation(nums.size).to_a.uniq, ops.permutation(ops.size).to_a.uniq
anums
#=> [["1", "2", "3", "4"], ["1", "2", "4", "3"], ["1", "3", "2", "4"],
# ["1", "3", "4", "2"], ["1", "4", "2", "3"], ["1", "4", "3", "2"],
# ["2", "1", "3", "4"], ["2", "1", "4", "3"], ["2", "3", "1", "4"],
# ["2", "3", "4", "1"], ["2", "4", "1", "3"], ["2", "4", "3", "1"],
# ["3", "1", "2", "4"], ["3", "1", "4", "2"], ["3", "2", "1", "4"],
# ["3", "2", "4", "1"], ["3", "4", "1", "2"], ["3", "4", "2", "1"],
# ["4", "1", "2", "3"], ["4", "1", "3", "2"], ["4", "2", "1", "3"],
# ["4", "2", "3", "1"], ["4", "3", "1", "2"], ["4", "3", "2", "1"]]
aops
#=> [["*", "/", "+"], ["*", "+", "/"], ["/", "*", "+"],
# ["/", "+", "*"], ["+", "*", "/"], ["+", "/", "*"]]
a = anums.product(aops).map { |an,ao|
([an.first] + ao.zip(an[1..-1]).map(&:join)).join }
#=> ["1*2/3+4", "1*2+3/4", "1/2*3+4",..., "4/3+2*1", "4+3*2/1", "4+3/2*1"]
a.size
#=> 144
I'm having some issues trying to sort a list of structs in Elixir...
I can't find out what I'm doing wrong.
IO.puts "########### MY TOP 5 #############"
IO.inspect mytop5
IO.puts "================================="
sorted = Enum.sort_by(mytop5, &(&1.count))
IO.inspect sorted
IO.puts "------------------------"
Here's the result
iex(67)> ########### MY TOP 5 #############
iex(67)> [%{count: "3", from: "AUD", rate: 0.64536947, to: "EUR"},
%{count: "10", from: "USD", rate: 1.3876, to: "AUD"},
%{count: "11", from: "USD", rate: 0.89726335, to: "EUR"}]
iex(67)> =================================
iex(67)> [%{count: "3", from: "AUD", rate: 0.64536947, to: "EUR"},
%{count: "11", from: "USD", rate: 0.89726335, to: "EUR"},
%{count: "10", from: "USD", rate: 1.3876, to: "AUD"}]
iex(67)> ------------------------
while :
iex(3)> [%{plop: "aze", count: 5, name: "a"}, %{plop: "aze", count: 1, name: "p"}, %{plop: "aze", count: 45, name: "e"}] |> Enum.sort_by(&(&1.count))
[%{count: 1, name: "p", plop: "aze"}, %{count: 5, name: "a", plop: "aze"},
%{count: 45, name: "e", plop: "aze"}]
This is sorting based on count being a string:
Enum.sort(["3", "10", "5"])# ["10", "3", "5"]
Enum.sort([3, 10, 5]) # [3, 5, 10]
This is because "10" < "3" is true due to the first character:
Enum.sort(["30", "9", "10", "1", "100", "3"])
# ["1", "10", "100", "3", "30", "9"]
You can use String.to_integer/1 to convert it:
Enum.sort_by(mytop5, &(String.to_integer(&1.count)))
I would like to format numbers and output as groups of four so that it looks something like this:
1 2 3 4
5 6 7 8
9 10 11 12
13 14 15 16
I did:
def convert_to_array(str)
arr = str.split(' ')
new_arr = arr.sort_by(&:to_i)
#format(new_arr.to_s)
end
def str
string = <<-_END_
4 6 2 14
15 8 13 1
10 5 9 12
7 11 16 3
_END_
convert_to_array(string)
end
The output of this is:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
I used pp as the format method:
require 'pp'
def format(input)
string = input.to_s
pp string
end
However the output of this looks like:
"[\"1\", \"2\", \"3\", \"4\", \"5\", \"6\", \"7\", \"8\", \"9\", \"10\", \"11\", \"12\
", \"13\", \"14\", \"15\", \"16\"]"
How can I fix the formatting as to put it into groups of four like the above example?
You just need to add Enumerable#each_slice to your method. Since that returns an enumerator, you then need to tack on Enumerable#to_a.
def convert_to_array(str)
str.split.sort_by(&:to_i).each_slice(4).to_a
end
convert_to_array(string)
#=> [["1", "2", "3", "4"],
# ["5", "6", "7", "8"],
# ["9", "10", "11", "12"],
# ["13", "14", "15", "16"]]
Note that String#split with no argument is the same as split(/\s+/).
To display the results:
convert_to_array(string).each { |a| puts a.join(' ') }
1 2 3 4
5 6 7 8
9 10 11 12
13 14 15 16
For
string
#=> " 4 6 2 14\n 15 8 13 1\n 10 5 9 12\n 7 11 16 3\n"
we compute
a = string.split
#=> ["4", "6", "2", "14", "15", "8", "13", "1",
# "10", "5", "9", "12", "7", "11", "16", "3"]
b = a.sort_by(&:to_i)
#=> ["1", "2", "3", "4", "5", "6", "7", "8", "9",
# "10", "11", "12", "13", "14", "15", "16"]
c = b.each_slice(4)
#=> #<Enumerator: ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
# "11", "12", "13", "14", "15", "16"]:each_slice(4)>
c.to_a
#=> [["1", "2", "3", "4"],
# ["5", "6", "7", "8"],
# ["9", "10", "11", "12"],
# ["13", "14", "15", "16"]]
You can use each_slice
def put_slices(array)
array.each_slice(4) do |slice|
puts slice.join(' ')
end
end
put_slices(str)
I have two arrays like this:
["1","7","8","10"]
and
["1","2","3","6","9","11"]
These arrays represents ids from a class called Place that a user selected. I want to select the places ids with most votes. I tried transpose but as the arrays have different sizes, they cannot be transposed.
The expected output for this example is:
{ "1" => 2, "7" => 1, "8" => 1, "10" => 1, "2" => 1, "3" => 1, "6" => 1, "9" => 1, "11" => 1 }
You can join all arrays and calculate the number of identical elements like this:
arrays = [["1","7","8","10"], ["1","2","3","6","9","11"]].reduce(:+)
arrays.inject(Hash.new(0)) { |memo, e| memo.update(e => memo[e] + 1) }
# "{ "1" => 2, "7" => 1, "8" => 1, "10" => 1, "2" => 1, "3" => 1, "6" => 1, "9" => 1, "11" => 1 }"
Once you have this intermediate result use max_by to select the key with the max value from the hash:
arrays = [["1","7","8","10"], ["1","2","3","6","9","11"]].reduce(:+)
arrays.inject(Hash.new(0)) { |memo, e| memo.update(e => memo[e] + 1) }
.max_by { |_, count| count }[0]
#=> "1"
This is another way:
arr = [["1","7","8","10"], ["1","2","3","6","9","11"], ["1","2","7"]]
h = arr.flatten.sort_by(&:to_i).group_by(&:itself)
h.update(h) { |_,v| v.size }
#=> {"1"=>3, "2"=>2, "3"=>1, "6"=>1, "7"=>2, "8"=>1, "9"=>1, "10"=>1, "11"=>1}
The steps:
a = arr.flatten
#=> ["1", "7", "8", "10", "1", "2", "3", "6", "9", "11", "1", "2", "7"]
b = a.sort_by(&:to_i)
#=> ["1", "1", "1", "2", "2", "3", "6", "7", "7", "8", "9", "10", "11"]
h = b.group_by(&:itself)
#=> {"1"=>["1", "1", "1"], "2"=>["2", "2"], "3"=>["3"], "6"=>["6"],
# "7"=>["7", "7"], "8"=>["8"], "9"=>["9"], "10"=>["10"], "11"=>["11"]}
If you are using a version of Ruby prior to 2.2 (when Object#itself was introduced) you will need to instead write:
h = b.group_by { |s| s }
Lastly:
h.update(h) { |_,v| v.size }
#=> {"1"=>["1", "1", "1"], "2"=>["2", "2"], "3"=>["3"], "6"=>["6"],
# "7"=>["7", "7"], "8"=>["8"], "9"=>["9"], "10"=>["10"], "11"=>["11"]}
This uses the form of Hash#update (aka merge!) that employs a block (here { |_,v| v.size }) to determine the values of keys that are present in both hashes being merged (which in this case is all of the keys).
Update: the method Hash#transform_values made its debut in Ruby v2.4. This allows us to write the following.
arr.flatten.
sort_by(&:to_i).
group_by(&:itself).
transform_values(&:size)