ruby arrays count of most frequent element [duplicate] - ruby-on-rails

This question already has answers here:
How to find an item in array which has the most occurrences [duplicate]
(11 answers)
Closed 6 years ago.
I'm trying to figure out how to find a count of the most frequent element in an array of integers. I can think of a few methods that might be helpful but when I get to writing an expression inside the block I get complete lost on how to compare an element with the next and previous element. Any ideas? All help is really really appreciated!!!

An easy was is to determine all the unique values, convert each to its count in the array, then determine the largest count.
def max_count(arr)
arr.uniq.map { |n| arr.count(n) }.max
end
For example:
arr = [1,2,4,3,2,6,3,4,2]
max_count(arr)
#=> 3
There are three steps:
a = arr.uniq
#=> [1, 2, 4, 3, 6]
b = a.map { |n| arr.count(n) }
#=> [1, 3, 2, 2, 1]
b.max
#=> 3
A somewhat more efficient way (because the elements of arr are enumerated only once) is to use a counting hash:
def max_count(arr)
arr.each_with_object(Hash.new(0)) { |n,h| h[n] += 1 }.values.max
end
max_count(arr)
#=> 3
We have:
a = arr.each_with_object(Hash.new(0)) { |n,h| h[n] += 1 }
#=> {1=>1, 2=>3, 4=>2, 3=>2, 6=>1}
b = a.values
#=> [1, 3, 2, 2, 1]
b.max
#=> 3
See Hash::new for an explanation of Hash.new(0). Briefly, if h = Hash.new(0) and h does not have a key k, h[k] will return the default value, which here is zero. h[k] += 1 expands to h[k] = h[k] + 1, so if h does not have a key k, this becomes h[k] = 0 + 1. On the other hand, if, say, h[k] => 2, then h[k] = h[k] + 1 #=> h[k] = 3 + 1.

Related

How to optimize the program with two for loops

I have a following programm
def calc_res(a)
n = a.length
result = 0
for i in 0 .. (n - 1)
for j in i .. (n - 1)
if (a[i] != a[j] && j - i > result) then
result = j - i
end
end
end
return result
end
which return following output
irb(main):013:0> calc_res([4, 6, 2, 2, 6, 6, 4])
=> 5
but it is taking time if array size is too large e.g. [0,1,2,3,.....70000]
can any one suggest me how can I optimize it.
Thanks
If I have understood the problem you are trying to solve (from code)
def calc_res(a)
last_index = a.length - 1
index = 0
while a[index] == a.last do
index = index + 1
break if index == last_index
end
last_index - index
end
It checks items from start if they are equal to items from end, end it moves the index toward the last element. As I understood you search for max length between different elements.
For you problem with [4, 6, 2, 2, 6, 6, 4] it will have one iteration and return 5, for the problem with [1...70000] it will have zero iterations and will return the difference in positions for those two (size of the array - 1)
My understanding is that the problem is to find two unique elements in the array whose distance apart (difference in indices) is maximum, and to return the distance they are apart. I return nil if all elements are the same.
My solution attempts to minimize the numbers of pairs of elements that must be examined before an optimal solution is identified. For the example given in the question only two pairs of elements need be considered.
def calc_res(a)
sz = a.size-1
sz.downto(2).find { |n| (0..sz-n).any? { |i| a[i] != a[i+n] } }
end
a = [4,6,2,2,6,6,4]
calc_res a
#=> 5
If sz = a.size-1, sz is the greatest possible distance two elements can be apart. If, for example, a = [1,2,3,4], sz = 3, which is the number of positions 1 and 4 are apart.
For a, sz = a.size-1 #=> 6. I first determine if any pair of elements that are n = sz positions apart are unique. [a[0], a[6]] #=> [4,4] is the only pair of elements 6 positions apart. Since they are not unique I reduce n by one (to 5) and examine all pairs of elements n positions apart, looking for one whose elements are unique. There are two pairs 5 positions apart: [a[0], a[5]] #=> [4,6] and [a[1], a[6]] #=> [6,4]. Both of these meet the test, so we are finished, and return n #=> 5. In fact we are finished after testing the first of these two pairs. Had neither these pairs contained unique values n would have been reduced by 1 to 4 and the three pairs [a[0], a[4]] #=> [4,6], [a[1], a[5]] #=> [6,6] and [a[2], a[6]] #=> [2,6] would have been searched for one with unique values, and so on.
See Integer#downto, Enumerable#find and Enumerable#any?.
A more rubyesque versions include:
def calc_res(a)
last = a.last
idx = a.find_index {|e| e != last }&.+(1) || a.size
a.size - idx
end
def calc_res(a)
last = a.last
a.size - a.each.with_index(1).detect(->{[a.size]}) {|e,_| e != last }.last
end
def calc_res(a)
last = a.last
a.reduce(a.size) do |memo, e|
return memo unless e == last
memo -= 1
end
end
def calc_res(a)
return 0 if b = a.uniq and b.size == 1
a.size - a.index(b[-1]).+(1)
end

How do I split a string given an array of split positions?

I'm using Ruby 2.4 and Rails 5. I have an array of indexes within a line
[5, 8, 10]
How do I take the above array, and a string, and form anotehr array of strings that are split by the above indexes? FOr instance, if the string is
abcdefghijklmn
and split it based ont eh above indexes, I would have an array with the following strings
abcde
fgh
ij
klmn
Try this
str = "abcdefghijklmn"
positions = [5, 8, 10]
parts = [0, *positions, str.size].each_cons(2).map { |a, b| str[a...b] }
# => ["abcde", "fgh", "ij", "klmn"]
Or,
If the positions are constant and known ahead of runtime (for example if they were the format for a phone number or credit card) just use a regexp
str.match(/(.....)(...)(..)(.*)/).captures
# => ["abcde", "fgh", "ij", "klmn"]
This will get the Job done
str = "abcdefghijklmn"
arr_1 = [5, 8, 10]
arr_2, prev = [], 0
(arr_1.length + 1).times do |x|
if arr_1[x] == nil then arr_1[x] = str.size end
arr_2 << str[prev..arr_1[x] -1]
prev = arr_1[x]
end
p arr_2
---------------------------------------
Program Run Output
["abcde", "fgh", "ij", "klmn"]
---------------------------------------
I hope this Helps

Random sum of elements in an array equals to y - ruby [duplicate]

This question already has answers here:
Finding all possible combinations of numbers to reach a given sum
(32 answers)
Closed 6 years ago.
Need to create an array whose sum should be equal to expected value.
inp = [1,2,3,4,5,6,7,8,9,10]
sum = 200
output:
out = [10,10,9,1,3,3,3,7,.....] whose sum should be 200
or
out = [10,7,3,....] Repeated values can be used
or
out = [2,3,4,9,2,....]
I tried as,
arr = [5,10,15,20,30]
ee = []
max = 200
while (ee.sum < max) do
ee << arr.sample(1).first
end
ee.pop(2)
val = max - ee.sum
pair = arr.uniq.combination(2).detect { |a, b| a + b == val }
ee << pair
ee.flatten
Is there any effective way to do it.
inp = [1,2,3,4,5,6,7,8,9,10]
sum = 20
inp.length.downto(1).flat_map do |i|
inp.combination(i).to_a # take all subarrays of length `i`
end.select do |a|
a.inject(:+) == sum # select only those summing to `sum`
end
One might take a random element of resulting array.
result = inp.length.downto(1).flat_map do |i|
inp.combination(i).to_a # take all subarrays of length `i`
end.select do |a|
a.inject(:+) == sum # select only those summing to `sum`
end
puts result.length
#⇒ 31
puts result.sample
#⇒ [2, 4, 5, 9]
puts result.sample
#⇒ [1, 2, 3, 6, 8]
...
Please note, that this approach is not efficient for long-length inputs. As well, if any original array’s member might be taken many times, combination above should be changed to permutation, but this solution is too ineffective to be used with permutation.
I found an answer of this question in the following link:
Finding all possible combinations of numbers to reach a given sum
def subset_sum(numbers, target, partial=[])
s = partial.inject 0, :+
#check if the partial sum is equals to target
puts "sum(#{partial})=#{target}" if s == target
return if s >= target #if we reach the number why bother to continue
(0..(numbers.length - 1)).each do |i|
n = numbers[i]
remaining = numbers.drop(i+1)
subset_sum(remaining, target, partial + [n])
end
end
subset_sum([1,2,3,4,5,6,7,8,9,10],20)

Select method with args separated by double-pipes only checking first element... Alternative?

I have a bit of broken legacy code I have to fix. Its purpose was to take a large array and return elements that have a particular sector number.
Here's a simplified version of the code in the app. Goal: return any instance of 1 or 3 in array:
array = [1,1,2,2,3,3].select{|num| num == (1 || 3) }
But the return value is simply #=> [1, 1] when the desired return was #=> [1, 1, 3, 3]
Basically, what I'm looking for is the Ruby equivalent to the following SQL query:
SELECT num FROM array
WHERE num IN (1, 3);
Ruby 1.8.7, Rails 2.3.15
Do as below to meet your need :
array = [1,1,2,2,3,3]
array.select{|num| [1,3].include? num }
# => [1, 1, 3, 3]
See why you got only [1,1].
1 || 3 # => 1
1 || 3 will always returns 1, thus num == 1 is evaluated as true when select is passing only 1. As a result you got [1,1].

Splitting/Slicing array in ruby

I've found this similar two questions to the one I'm about to ask:
Split array up into n-groups of m size?
and
Need to split arrays to sub arrays of specified size in Ruby
This splits array into three arrays with each array having three elements :
a.each_slice(3) do |x,y,z|
p [x,y,z]
end
So if I do this (my array size is 1000) :
a.each_slice(200) do |a,b,c,d,e|
p "#{a} #{b} #{c} #{d} #{e}"
end
This should split my array into 5 arrays each having 200 members? But it doesn't?
What I actually need to do is to put 200 random elements into 5 arrays, am I on the right track here, how can I do this?
Enumerable#each_slice
If you provide a single argument to the block of each_slice then it will fill that argument with an array of values less than or equal to the given argument. On the last iteration if there are less than n values left then the array size will be whatever is left.
If you provide multiple arguments to the block of each_slice then it will fill those values with the values from the source array. If the slice size is greater than the number of arguments given then some values will be ignored. If it is less than the number of arguments than the excess arguments will be nil.
a = (1..9).to_a
a.each_slice(3) {|b| puts b.inspect }
[1,2,3]
[4,5,6]
[7,8,9]
a.each_slice(4) {|b| puts b.inspect }
[1,2,3,4]
[5,6,7,8]
[9]
a.each_slice(3) {|b,c,d| puts (b + c + d)}
6 # 1 + 2 + 3
15 # 4 + 5 + 6
24 # 7 + 8 + 9
a.each_slice(3) {|b,c| puts (b + c)}
3 # 1 + 2, skips 3
9 # 4 + 5, skips 6
15 # 7 + 8, skips 9
a.each_slice(2) {|b,c| puts c.inspect}
2
4
6
8
nil
a.each_slice(3) {|b,c,d,e| puts e.inspect}
nil
nil
nil
irb(main):001:0> a= (1..10).to_a
=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
irb(main):002:0> a.sample(3)
=> [5, 10, 1]
irb(main):003:0> (1..3).map{ a.sample(3) }
=> [[6, 2, 5], [8, 7, 3], [4, 5, 7]]
irb(main):004:0>
Actually you will return a string with the five elements inserted in it.
You can try something:
a1 = [], a2 = [], a3 = [], a4 = [], a5 = []
a.each_slice(5) do |a,b,c,d,e|
a1 << a
a2 << b
a3 << c
a4 << d
a5 << e
end
You will end up with five arrays containing 200 elements each.
I used the simplest possible syntax to make it clear, you can
make it much more condensed.
If you want to assign that result to 5 different arrays, you could use the splat operator,like this:
a,b,c,d,e = *(1..1000).each_slice(200).to_a

Resources