ruby: index of all elements in array lesser than given value - ruby

I have an array
a=[10,20,30,10,3,2,200]
I want to find indexes of the element having value less than , say 21. I can surely do this in loop, but i was wondering if there is better one liner approach of it. Like we have in R.

Do as below using Array#each_index:
a = [10,20,30,10,3,2,200]
a.each_index.select { |i| a[i] < 21 }
# => [0, 1, 3, 4, 5]
I am using ruby 1.8.5
Then do
a = [10,20,30,10,3,2,200]
a.size.times.select { |i| a[i] < 21 }
# => [0, 1, 3, 4, 5]

Here are some more choices for those occasions when a straigtforward solution just won't do:
a = [10,20,30,10,3,2,200]
a.size.times.with_object([]) { |i,b| b << i if a[i] < 21 } # or a.each_index.with...
a.size.times.map { |i| a[i] < 21 ? i : nil }.compact # or a.each_index.with...
a.zip( Array(0...a.size) ).select { |e,_| e < 21 }.map(&:last)
a.reduce([[],0]) { |(b,i),e| [e < 21 ? b << i : b, i + 1] }.first
a.each_with_object([]) {|e,a| a << (e.to_i < 21 ? a.size : nil) }.compact
a.each_with_object([[],[]]) {|e,(g,b)|
e < 21 ? g << (g.size + b.size) : b << nil }.first
(a.each_with_object([-1]) { |_,b| i = a[b.last+1..-1].index {
|f| f < 21 }; b << b.last + 1 + i if i })[1..-1]
b = a.dup
a.each_with_object([]) { |e,c| i = b.index(e); c << i if e < 21; b[i] = nil }
b = (a + [nil])
a.each.with_object([]) { |_,c|
c << (a.size - b.index(nil)) if b.first.to_i < 21; b.rotate! }
a.join(',').gsub(/(\d+)/) { |e| (e.to_i < 21) ? $`.count(',') : nil } \
.gsub(',,',',').split(',').map(&:to_i)
# All => [0, 1, 3, 4, 5]

This should do the trick and is linear:
a.each_with_index.inject([]) {|indexes, pair| indexes << pair.last if pair.first < 21; indexes}

Ruby usually do not need to find indexes, why are you trying to do it?
This should work fine in 1.8:
[10,20,30,10,3,2,200].each_with_index.select{|x,_|x<21}.map{|_,i|i}

Related

stdout can print correct result but not output in ruby although i have return the values

def two_sum(nums, target)
for i in 0..3 - 1
for j in 0..3 - 1
if nums[i] + nums[j] == target && i < j && i != j
puts '[' + (i - 1).to_s + ',' + (j - 1).to_s + ']'
end
end
end
return (i - 1), (j - 1)
end
def main()
nums = Array.new()
target = gets().to_i
nums = gets().to_i
two_sum(nums, target)
end
main()
The requirement of the exercise is to print out numbers whose sum is equal to a target number. You need to get an array of integers and the target number at first.
Can anyone debug it for me? Thank you.
I will leave it others to debug your code. Instead I would like to suggest another way that calculation could be made relatively efficiently.
def two_sum(nums, target)
h = nums.each_with_index.with_object(Hash.new { |h,k| h[k] = [] }) do |(n,i),h|
h[n] << i
end
n,i = nums.each_with_index.find { |n,_i| h.key?(target-n) }
return nil if n.nil?
indices = h[target-n]
return [i,indices.first] unless n == target/2
return nil if indices.size == 1
[i, indices.find { |j| j !=i }]
end
​
two_sum([2,7,11,15], 9) #=> [0, 1]
two_sum([2,7,11,15], 10) #=> nil
two_sum([2,7,11,15], 4) #=> nil
two_sum([2,7,11,2,15], 4) #=> [0, 3]
two_sum([2,11,7,11,2,15,11], 22) #=> [1, 3]
In the last example
h #=> {2=>[0, 4], 11=>[1, 3, 6], 7=>[2], 15=>[5]}
Note that key lookups in hashes are very fast, specifically, the execution of the line
indices = h[target-n]
Building h has a computational complexity of O(n), where n = num.size and the remainder is very close to O(n) ("very close" because key lookups are close to constant-time), the overall computational complexity is close to O(n), whereas a brute-force approach considering each pair of values in num is O(n^2).
If a hash is defined
h = Hash.new { |h,k| h[k] = [] }
executing h[k] when h has no key k causes
h[k] = []
to be executed. For example, if
h #=> { 2=>[0] }
then
h[11] << 1
causes
h[11] = []
to be executed (since h does not have a key 11), after which
h[11] << 1
is executed, resulting in
h #=> { 2=>[0], 11=>[1] }
By contrast, if then
h[2] << 3
is executed we obtain
h #=> { 2=>[0,3], 11=>[1] }
without h[2] = [] being executed because h already has a key 2. See Hash::new.
Expressing block variables as
|(n,i),h|
is a form of array decomposition.

Ruby - Can't replace last range's element with another one

So I want to merge overlapping ranges and it should like the following:
Input: ranges = [(1..2), (3..6), (5..8)]
Output: expected = [(1..2), (3..8)]
but when the code iterate over the intervals and goes to the else statement I just get a message "function_merge.rb:9:in block in merge': undefined methodend=' for 2..19:Range (NoMethodError)"
I tried to save merged.last.end and interval.end to variables, rewrote the if statement over couple of lines (if interval.end > merged.last.end merged.last.end = interval.end end) but all that didn't work :-(
def merge(intervals)
merged = []
intervals.sort_by! { |interval| interval.begin }
intervals.each do |interval|
if merged.empty? || merged.last.end < interval.begin
merged << interval
else
merged.last.end = interval.end if interval.end > merged.last.end
end
end
return merged
end
I don't understand why I get this error message since "end" is a range method? I just want to "update" the merged.last.end with the interval.end number.
If you have any tips how to solve it, would be very nice :-)
As Sebastian points out, Ranges are immutable. Instead of trying to change the Range you'll have to make a new one.
def merge(intervals)
merged = []
intervals.sort_by! { |interval| interval.begin }
intervals.each do |interval|
if merged.empty? || merged.last.end < interval.begin
merged << interval
else
merged[-1] = Range.new(merged.last.begin, interval.end, interval.exclude_end?)
end
end
return merged
end
It has been explained that ranges are immutable. The question implies the elements covered by the ranges are all comparable (e.g, not ['a'..'z', 1..10]). I assume that the array of ranges does not contain a mix of finite and infinite ranges.
Solution
Code
def distill(arr)
a = arr.reject { |r| r.exclude_end? ? (r.end <= r.begin) : r.end < r.begin }.
sort_by(&:begin)
return [] if a.empty?
combined = []
curr = a.shift
loop do
break (combined << curr) if a.empty?
nxt = a.shift
if nxt.begin > curr.end
combined << curr
curr = nxt
else
last = [curr, nxt].max_by { |r| [r.end, r.exclude_end? ? 0 : 1] }
curr = last.exclude_end? ? (curr.begin...last.end) :
curr.begin..last.end
end
end
end
Examples
distill [5..8, 7...9, 9..11, 1...4, 38..37]
#=> [1...4, 5..11]
distill [1.5...2.2, 2.2..3.0, 3.0...4.5, 4.7..5.3, 5.2..4.6]
#=> [1.5...4.5, 4.7..5.3]
distill ['a'..'d', 'c'..'f', 'b'..'g']
# 'a'..'g'
Explanation
See Range#exclude_end?.
The steps for the first example are as follows.
arr = [5..8, 7...9, 9..11, 1...4, 38..37]
a = arr.reject { |r| r.exclude_end? ? (r.end <= r.begin) : r.end < r.begin }.
sort_by(&:begin)
#=> [1...4, 5..8, 7...9, 9..11]
a.empty?
#=> false, so do not return
combined = []
curr = a.shift
#=> 1...4
a #=> [5..8, 7...9, 9..11]
The calculations within the loop can be best explained by salting the code with puts statements and displaying the results.
loop do
puts "a.empty? #=> true, so break #{combined + [curr]}" if a.empty?
break (combined << curr) if a.empty?
puts "a.empty? #=> false"
nxt = a.shift
puts "nxt=#{nxt}, a=#{a}"
puts "nxt.begin=#{nxt.begin} > #{curr.end} = curr.end = #{nxt.begin > curr.end}"
if nxt.begin > curr.end
combined << curr
puts "combined << #{curr} = #{combined}"
curr = nxt
puts "curr = nxt = #{curr}"
else
last = [curr, nxt].max_by { |r| [r.end, r.exclude_end? ? 0 : 1] }
puts "last=#{last}, last.exclude_end?=#{last.exclude_end?}"
curr = last.exclude_end? ? (curr.begin...last.end) :
curr.begin..last.end
puts "new value of curr=#{curr}"
end
puts
end
a.empty? #=> false
nxt=5..8, a=[7...9, 9..11]
nxt.begin=5 > 4 = curr.end = true
combined << 1...4 = [1...4]
curr = nxt = 5..8
a.empty? #=> false
nxt=7...9, a=[9..11]
nxt.begin=7 > 8 = curr.end = false
last=7...9, last.exclude_end?=true
new value of curr=5...9
a.empty? #=> false
nxt=9..11, a=[]
nxt.begin=9 > 9 = curr.end = false
last=9..11, last.exclude_end?=false
new value of curr=5..11
a.empty? #=> true, so break [1...4, 5..11]
It is sometimes convenient to be able to return an empty (but valid) range such as 38..37; one should not think of empty ranges as necessarily being an indication that something is amiss.
Alternative solution
If the ranges are all finite, as in the example, and the combined sizes of the ranges is not excessive, one could write the following.
Code
def distill(arr)
arr.flat_map(&:to_a).
uniq.
sort.
chunk_while { |x,y| y == x.next }.
map { |a| a.first..a.last }
end
Examples
distill [5..8, 7...9, 9..11, 1...4, 38..37]
#=> [1..3, 5..11]
distill ['a'..'d', 'c'..'f', 'b'..'g']
# 'a'..'g'
Explanation
The steps for the first example are as follows.
arr = [5..8, 7...9, 9..11, 1...4, 38..37]
a = arr.flat_map(&:to_a)
#=> => [5, 6, 7, 8, 7, 8, 9, 10, 11, 1, 2, 3]
b = a.uniq
#=> [5, 6, 7, 8, 9, 10, 11, 1, 2, 3]
c = b.sort
#=> [1, 2, 3, 5, 6, 7, 8, 9, 10, 11]
d = c.chunk_while { |x,y| y == x.next }
#=> #<Enumerator: #<Enumerator::Generator:0x00005c2683af8dd0>:each>
e = d.map { |a| a.first..a.last }
#=> [1..3, 5..11]
One can convert the enumerator d to an array to see the elements it will generate and pass to chunk_while's block:
d.to_a
#=> [[1, 2, 3], [5, 6, 7, 8, 9, 10, 11]]
See Enumerable#chunk_while. One could alternatively use Enumerable#slice_when.

Decompose string to form a valid expression

I am given a string S (of integers) and a number N. I want to insert arbitrary number of '+' in S so that the sum becomes equal to N.
Ex:<br>
S = 15112 and N = 28<br>
Ans is : 15+11+2<br>
S = 120012 and N = 33<br>
Ans is : 1+20+012<br>
S = 123 and N = 123<br>
Ans is : 123
given : |S| <= 120 and N <= 10^6
It is guarenteed that S and N are given such that it is always possible to form valid expression. Is there any algorithm which can solve this? I tried to think on it but couldn't come up with solution.
There may be more efficient ways to do this, but since you have nothing so far…
You can simply find all combinations of a boolean array that indicates whether a plus should exist between the numbers or not.
For example: with an input of 112134, 1 + 12 + 13 + 4 can be represented with the boolean array [true, false, true, false, true] indicating that there is a plus after the 1st, 3rd, and 5th numbers. The problem then reduces to finding which combinations add to your number. There are lot of ways to find combinations. Recursive backtracking is a classic.
In javascript/node this might look like this:
function splitOnIndexes(arr, a) {
// split the array into numbers based on the booleans
let current = "" + arr[0]
let output = []
for (let i = 0; i < a.length; i++) {
if (!a[i]) {
current += arr[i + 1]
} else {
output.push(current)
current = "" + arr[i + 1]
}
}
output.push(current)
return output
}
function findSum(input, total) {
function backtrack(n, k = 0, a = []) {
const sum = (arr) => arr.reduce((a, c) => a + parseInt(c), 0)
if (k === n) {
let ans = splitOnIndexes(input, a)
if (sum(ans) === total) {
console.log(ans.join(' + '))
}
} else {
k = k + 1
let c = [true, false]
for (let i = 0; i < 2; i++) {
a[k - 1] = c[i]
backtrack(n, k, a)
}
}
}
backtrack(input.length - 1)
}
findSum('15112', 28)
findSum('120012', 33)
findSum('123', 123)
As you can see, more than one answer is possible. Your first example is solved with both 15+1+12 and 15+11+2. If you only need one, you can of course stop early.
The idea is to use dynamic programming, you only care about sums between 0 and 10^6 and only have 120 possible indexes. if dp[i][j] = x, it means that from index x of the string, we went to index i (so we added a + before i) and we got a sum of j. This leads to a O(|S| * N) solution:
#include <iostream>
#include <string>
#include <vector>
using namespace std;
string s;
long n;
long dp[123][1000001];
void solve (int index, long sum) {//index = what index of s still remains to scan. sum = the sum we have accumulated till now
if (sum >= n or index >= s.length()) return;
if (dp[index][sum] != -1) return;
if (index == n and sum == n) return;
long num = 0;
for (int i = 0; i < 7 && index + i < s.length(); i++) { //N has 6 digits at most
num = stoi(s.substr(index, i + 1));
solve(index + i + 1, sum + num);
if (sum + num <= n) {
dp[index + i + 1][sum + num] = index;
}
}
}
int main () {
cin >> s;
cin >> n;
for (int i = 0; i < 121; i++) {
for (int j = 0; j < 1000001; j++) {
dp[i][j] = -1;
}
}
solve(0, 0);
int sum = n;
int idx = s.length();
vector<string> nums;
//reconstruct solution
while (idx != 0) {
nums.push_back(s.substr(dp[idx][sum], idx - dp[idx][sum]));
idx = dp[idx][sum];
sum -= stoi(nums[nums.size() - 1]);
}
for (int i = nums.size() -1; i >= 0; i--) {
cout << nums[i];
if (i != 0) cout << "+";
}
}
This is a Ruby version with step by step explanation of the algorithm, so you can easily code in C++ (or I'll try later).
# Let's consider that we extracted the values from text, so we already have the string of int and the result as integer:
string_of_int = "15112"
result = 28
# The basic idea is to find a map (array) that tells how to group digits, for example
sum_map = [2, 1, 2]
# This means that string_of_int is mapped into the following numbers
# 15, 1, 12
# then sum the numbers, in this case 15+1+12 = 28
# For finding a the solution we need to map
# all the possible combinations of addition given the n digits of the string_of_int then check if the sum is equal to the result
# We call k the number of digits of string_of_int
# in ruby we can build an array called sum_maps
# containing all the possible permutations like this:
k = string_of_int.length # => 5
sum_maps = []
k.times do |length|
(1..k).to_a.repeated_permutation(length).each {|e| sum_maps << e if e.inject(:+) == k}
end
sum_maps
# => [[1, 5], [2, 4], [3, 3], [4, 2], [5, 1], [1, 1, 4], [1, 2, 3], [1, 3, 2], [1, 4, 1], [2, 1, 3], [2, 2, 2], [2, 3, 1], [3, 1, 2], [3, 2, 1], [4, 1, 1]]
# Now must check which of of the sum_map is giving us the required result.
#
# First, to keep the code short and DRY,
# better to define a couple of useful methods for the String class to use then:
class String
def group_digits_by(sum_map)
string_of_int_splitted = self.split("")
grouped_digits = []
sum_map.each { |n| grouped_digits << string_of_int_splitted.shift(n).join.to_i}
grouped_digits.reject { |element| element == 0 }
end
def sum_grouped_of_digits_by(sum_map)
group_digits_by(sum_map).inject(:+)
end
end
# So we can call the methods directly on the string
# for example, in ruby:
string_of_int.group_digits_by sum_map #=> [15, 1, 12]
string_of_int.sum_grouped_of_digits_by sum_map #=> 28
# Now that we have this metods, we just iterate through the sum_maps array
# and apply it for printing out the sm_map if the sum of grouped digits is equal to the result
# coded in ruby it is:
combinations = []
sum_maps.each { |sum_map| combinations << string_of_int.group_digits_by(sum_map) if string_of_int.sum_grouped_of_digits_by(sum_map) == result }
p combinations.uniq
# => [[15, 1, 12], [15, 11, 2]]
In short, written as a Ruby module it becomes:
module GuessAddition
class ::String
def group_digits_by(sum_map)
string_of_int_splitted = self.split("")
grouped_digits = []
sum_map.each { |n| grouped_digits << string_of_int_splitted.shift(n).join.to_i}
grouped_digits.reject { |element| element == 0 }
end
def sum_grouped_of_digits_by(sum_map)
group_digits_by(sum_map).inject(:+)
end
end
def self.guess_this(string_of_int, result)
k = string_of_int.length
sum_maps = []
k.times { |length| (1..k).to_a.repeated_permutation(length).each {|e| sum_maps << e if e.inject(:+) == k} }
combinations = []
sum_maps.each { |sum_map| combinations << string_of_int.group_digits_by(sum_map) if string_of_int.sum_grouped_of_digits_by(sum_map) == result }
combinations.uniq
end
end
p GuessAddition::guess_this("15112", 28) # => [[15, 1, 12], [15, 11, 2]]

Comparing two arrays with each other

I am trying to solve some problems in ruby get a hold.
I am trying compare two arrays with each other.
Array1 = [1,0,1,0,1,1]
Array2= [0,0,1,0,1,0]
I am getting this input from the user. Then I am comparing the votes. If both persons have upvoted 1 at same index, I am trying increment an empty array by 1.
def count_votes
bob_votes = gets.chomp
alice_votes = gets.chomp
bvotes = bob_votes.split('')
avotes = alice_votes.split('')
common_upvotes = []
bvotes.each.with_index(0) do |el, i|
if bvotes[i] == 1
common_upvotes << 1
end
end
I actually want to compare avotes with bvotes and then increment empty array by 1. I need a little help
You can use Array#zip and Enumerable#count:
array1 = [1,0,1,0,1,1]
array2= [0,0,1,0,1,0]
array1.zip(array2)
#⇒ [[1, 0], [0, 0], [1, 1], [0, 0], [1, 1], [1, 0]]
array1.zip(array2).count { |v1, v2| v1 == v2 && v1 == 1 }
#⇒ 2
or (credits to #engineersmnky):
array1.zip(array2).count { |v1, v2| v1 & v2 == 1 }
or even better (credits to #Stefan):
array1.zip(array2).count { |values| values.all?(1) }
or
array1.
zip(array2).
reject { |v1, v2| v1 == 0 || v2 == 0 }.
count
#⇒ 2
Sidenote: capitalized Array1 declares a constant. To declare a variable, use array1 instead.
The number of indices i for which Array1[i] == 1 && Array2[i] == 1 is
Array1.each_index.count { |i| Array1[i] == 1 && Array2[i] == 1 }
#=> 2
The array of indices i for which Array1[i] == 1 && Array2[i] == 1 is
Array1.each_index.select { |i| Array1[i] == 1 && Array2[i] == 1 }
#=> [2, 4]
The number of indices i for which Array1[i] == Array2[i] is
Array1.each_index.count { |i| Array1[i] == Array2[i] }
#=> 4
If you want to build a new array tracking the index where there is a match of upvotes:
a1 = [1,0,1,0,1,1]
a2= [0,0,1,0,1,0]
p [a1, a2].transpose.map {|x| x.reduce(:&)}
#=> [0, 0, 1, 0, 1, 0]
For just counting, this is another way:
a1 = [1,0,1,0,1,1]
a2= [0,0,1,0,1,0]
votes = 0
a1.each_with_index do |a1, idx|
votes +=1 if (a1 + a2[idx]) == 2
end
p votes #=> 2
In one line:
a1.each_with_index { |a1, idx| votes += 1 if (a1 + a2[idx]) == 2 }

How to return the elements in the array that the variable falls between

I have a unique sorted array: [2,4,6,8,10].
I have a variable called i. If i is 5, I want to return the elements in the array that 5 falls between. In this case [4,6]. If i is 8, then [8,10].
How should I go about this?
I've tried with partition, to some extent. If i happens to be a number directly equal to one of the values in the array. This seems to work:
a=[2,4,6,8,10]
i = 6
a.partition { |v| v < i }.max[0..1] # returns [6,8]
However, if i is a number not directly equal to any of the values in the array. For example 5, it gets a little trickier.
I got it working for the last case:
a=[2,4,6,8,10]
i = 5
partition = a.partition { |v| v < i }
[].tap { |a| a << partition[0].max; a << partition[1].min } # returns [6,8]
While this works, I am looking to see if there is a better way to write this logic.
You could use Enumerable#each_cons.
def mind_the_gap(arr, n)
arr.each_cons(2).find { |l,u| l <= n && n < u }
end
arr = [2,4,6,8,10]
mind_the_gap(arr, 5) #=> [4,6]
mind_the_gap(arr, 8) #=> [8,10]
mind_the_gap(arr, 1) #=> nil
mind_the_gap(arr, 10) #=> nil
If you don't want the last two examples to return nil, you could change the method as follows.
def mind_the_gap(arr, n)
rv = arr.each_cons(2).find { |l,u| l <= n && n < u }
return rv unless rv.nil?
n < arr.first ? :low : :high
end
mind_the_gap(arr, 5) #=> [4,6]
mind_the_gap(arr, 8) #=> [8,10]
mind_the_gap(arr, 1) #=> :low
mind_the_gap(arr, 10) #=> :high
Another way is to use Enumerable#slice_when.
def mind_the_gap(arr, n)
a = arr.slice_when { |l,u| l <= n && n < u }.to_a
return [a.first.last, a.last.first] unless a.size == 1
n < arr.first ? :low : :high
end
mind_the_gap(arr, 5) #=> [4,6]
mind_the_gap(arr, 8) #=> [8,10]
mind_the_gap(arr, 1) #=> :low
mind_the_gap(arr, 10) #=> :high
If you're looking for elements inside a sorted array, the "better way" probably involves bsearch or bsearch_index.
The second element in the pair is the first element in the array that is greater than your variable, so bsearch_index can return it directly. You need to check it isn't nil or 0 before returning the found element and the previous one :
a = [2, 4, 6, 8, 10]
def find_surrounding_pair(array, element)
second_index = array.bsearch_index { |x| x > element }
array[second_index - 1, 2] if second_index && second_index > 0
end
puts find_surrounding_pair(a, 1).nil?
puts find_surrounding_pair(a, 2) == [2, 4]
puts find_surrounding_pair(a, 7) == [6, 8]
puts find_surrounding_pair(a, 8) == [8, 10]
puts find_surrounding_pair(a, 12).nil?
#=> true * 5
The complexity of this method should be O(log n).
what about this
val = 5
a = [2,4,6,8,10] # assuming it's sorted
a.slice(a.rindex {|e| e <= val}, 2)
It doesn't account for the case when the lookup value is equal or bigger the last element of the array. I'd probably append a nil element for this, if that would be appropriate for the problem.
This looks like a good use to check for the inclusion in a range:
a = [2,4,6,8,10]
b = 5
a.each_cons(2).select { |i, j| (i .. j) === b }
# => [[4, 6]]
It's not clear exactly what you mean by "falls between". In the code above 8 would fall between two sets of numbers:
b = 8
a.each_cons(2).select { |i, j| (i .. j) === b }
# => [[6, 8], [8, 10]]
if the test is i <= b <= j. If it's i <= b < j then use ... instead of ..:
a.each_cons(2).select { |i, j| (i ... j) === b }
# => [[8, 10]]
I'm not a big fan of using ... but it simplifies the code.
From the Range documentation:
Ranges constructed using .. run from the beginning to the end inclusively. Those created using ... exclude the end value.
You could change that to:
a.each_cons(2).select { |i, j| i <= b && b <= j }
or:
a.each_cons(2).select { |i, j| i <= b && b < j }
if those work better for your mind. Using a Range is a little slower, but not radically so.

Resources