Subtract Range of Numbers Algorithm - ruby

How would I accomplish the following: Take one array of ranges and subtract another array of ranges from it.
For example:
arr0 = [[0,50],[60,80],[100,150]] # 0-50, 60-80, etc.
arr1 = [[4,8],[15,20]] # 4-8, 15-20, etc.
# arr0 - arr1 magic
result = [[0,3],[9,14],[21,50],[60,80],[100,150]] # 0-3, 9-14, etc.
What's the cleanest and most efficient way to do this in Ruby?

This is a deliberately naïve solution. It's not efficient, but easy to comprehend and quite short.
Deconstruct arr0 into a list of numbers:
n1 = arr0.flat_map { |a, b| (a..b).to_a }
#=> [0, 1, ..., 49, 50, 60, 61, ..., 79, 80, 100, 101, ..., 149, 150]
Same for arr1:
n2 = arr1.flat_map { |a, b| (a..b).to_a }
#=> [4, 5, 6, 7, 8, 15, 16, 17, 18, 19, 20]
Then, subtract n2 from n1 and recombine consecutive numbers:
(n1 - n2).chunk_while { |a, b| a.succ == b }.map(&:minmax)
#=> [[0, 3], [9, 14], [21, 50], [60, 80], [100, 150]]

Related

Generate numbers from n to m from a list

I'll start with an example; given n = 1 and m = 100 and a list [1, 2, 3]
generate all numbers with 1 digit and two digits and so on but they need to be less then 100 in this case.
Output:
- 1, 2, 3, 11, 12, 13, 21, 22, 23, 31, 32, 33
Then we stop because the next numbers will over 100, e.g:
- 111, 112, 113, 121, 122, 123, 131, 132, 133, 21..,. 22..., 23..., 31, 32, 33
As you noticed I am appending 1, 2, 3, 4 to a number created before, to do this I am using a recursive function, which is started in a for loop for each number in my list, and they it runs till the generated numbers are greater then my limit.
def x(str, finish, d, c)
return if d >= finish
[1, 2, 3, 4].each do |e|
x(str, end, d*c+e)
end
# do something if d >= str
end
This works fine if I need to start from 1, but if my starting number is a lot bigger, I still need to start to create this sequence.
Can somebody help me with a solution that will produce the same sequences, but from any starting point rather then 1, so if for example the starting point was 100 and end 200 the output will be:
111, 112, 113, 114, 121, 122, 123, 124, 131, 132, 132 [...]
A solution in any programming language would be nice, but please not builtin core libraries.
Code
def generate_em(minimum, maximum, list)
digits_min = minimum.to_s.size
digits_min += 1 if minimum > (list.max.to_s*digits_min).to_i
digits_max = maximum.to_s.size
digits_max -= 1 if maximum < (list.min.to_s*digits_max).to_i
(digits_min..digits_max).each_with_object([]) { |n,arr|
arr.concat(list.repeated_permutation(n).to_a.map { |a| a.join.to_i }) }.
uniq.
select { |n| (minimum..maximum).cover?(n) }
end
Examples
#1
minimum = 1
maximum = 100
list = [1, 2, 3]
generate_em(minimum, maximum, list)
#=> [1, 2, 3, 11, 12, 13, 21, 22, 23, 31, 32, 33]
#2
minimum = 78
maximum = 3332
list = [3, 4, 5, 6, 7]
generate_em(minimum, maximum, list)
#=> [333, 334, 335, 336, 337, 343, 344, 345, 346, 347, 353, 354, 355, 356,
# 357, 363, 364, 365, 366, 367, 373, 374, 375, 376, 377, 433, 434, 435,
# 436, 437, 443, 444, 445, 446, 447, 453, 454, 455, 456, 457, 463, 464,
# 465, 466, 467, 473, 474, 475, 476, 477, 533, 534, 535, 536, 537, 543,
# 544, 545, 546, 547, 553, 554, 555, 556, 557, 563, 564, 565, 566, 567,
# 573, 574, 575, 576, 577, 633, 634, 635, 636, 637, 643, 644, 645, 646,
# 647, 653, 654, 655, 656, 657, 663, 664, 665, 666, 667, 673, 674, 675,
# 676, 677, 733, 734, 735, 736, 737, 743, 744, 745, 746, 747, 753, 754,
# 755, 756, 757, 763, 764, 765, 766, 767, 773, 774, 775, 776, 777]
#3
minimum = 0
maximum = 100
list = [0, 1, 2]
generate_em(minimum, maximum, list)
#=> [0, 1, 2, 10, 11, 12, 20, 21, 22, 100]
Explanation
Example #1
The steps for the first example above are as follows.
digits_min = minimum.to_s.size
#=> 1
Increase digits_min by one if mimimum is larger than the largest digits_min digits from list.
digits_min += 1 if minimum > (list.max.to_s*digits_min).to_i
digits_min
#=> 1
digits_max = maximum.to_s.size
#=> 3
Decrease digits_max by one if maximum is smaller than the smallest digits_max digits from list.
digits_max -= 1 if maximum < (list.min.to_s*digits_max).to_i
digits_max
#=> 2
We improve efficiency by having reduced digits_max from 3 to 2
c = digits_min..digits_max
#=> 1..2
d = c.each_with_object([])
#=> #<Enumerator: 1..2:each_with_object([])>
We can see the elements that will be generated by this enumerator by invoking Enumerable#entries (or Enumerable#to_a) on it.
d.entries
#=> [[1, []], [2, []]]
n, arr = d.next
#=> [1, []]
n #=> 1
arr
#=> []
e = list.permutation(n)
#=> #<Enumerator: [1, 2, 3]:permutation(2)>
f = e.to_a
#=> [[1], [2], [3]]
arr.concat f
#=> [[1], [2], [3]]
n, arr = d.next
#=> [2, [[1], [2], [3]]]
n #=> 2
arr
#=> [[1], [2], [3]]
e = list.permutation(n)
#=> #<Enumerator: [1, 2, 3]:permutation(2)>
f = e.to_a
#=> [[1, 2], [1, 3], [2, 1], [2, 3], [3, 1], [3, 2]]
arr.concat f
#=> [[1], [2], [3], [1, 2], [1, 3], [2, 1], [2, 3], [3, 1], [3, 2]]
arr is returned by each_with_object's block.
g = arr.map { |a| a.join.to_i }
#=> [1, 2, 3, 12, 13, 21, 23, 31, 32]
h = g.uniq
#=> [1, 2, 3, 12, 13, 21, 23, 31, 32]
h.select { |n| (minimum..maximum).cover?(n) }
#=> [1, 2, 3, 12, 13, 21, 23, 31, 32]
Example #2
In the second example no two-digit combinations are generated because
78 > (list.max.to_s*2).to_i
#=> 78 > 77 => true
and no four-digit combinations are generated because
3332 < (list.min.to_s*4).to_i
#=> 3332 < 3333 => true
Example #3
Without uniq, the method would have returned duplicate values:
[0, 1, 2, 0, 1, 2, 10, 11, 12, 20, 21, 22, 0, 1, 2, 10, 11, 12, 20, 21, 22, 100]
Since you wrote your example code in Ruby, you could use repeated_permutation :
def possible_numbers(arr, min, max)
min_digits = min.to_s.size
max_digits = max.to_s.size
(min_digits..max_digits).flat_map do |i|
arr.repeated_permutation(i)
.map { |digits| digits.join.to_i }
.select { |number| number >= min && number <= max }
.uniq
end
end
p possible_numbers([1, 2, 3], 100, 200)
# => [111, 112, 113, 121, 122, 123, 131, 132, 133]
So, this takes an input of the digits provided, makes all the digit combinations repeatedly until it reaches your max. You'll want to adjust them to include recovery and saves in the event non-integers are entered or if it's otherwise impossible to hit the max for some reason - but this is a solid framework.
digits = [1,2,3]
max = 100
def possible_numbers(arr, max)
loop do
arr.product(arr).each do |combo|
return arr.uniq if combo.join("").to_i > max
arr << combo.join("").to_i
end
end
end
possible_numbers(digits, max)
Output:
=> [1, 2, 3, 11, 12, 13, 21, 22, 23, 31, 32, 33]
You can proceed from "right" (least significant digit) to "left" (most significant digit), keeping track of two values:
min, the least valid integer that has the same number of digits as what you've processed so far. So, for example, if you've processed a trailing 27, then the least valid two-digit integer is 11.
max, the least valid integer that has the same number of digits as what you've processed so far and is greater than or equal to what you've processed so far. So, for example, if you've processed a trailing 27, then the least valid two-digit integer greater than or equal to 27 is 31.
Note that max won't always exist. For example, there's no valid two-digit integer greater than or equal to 70.
The reason you need min is that if you encounter a digit that's not in your list of allowed digits, then the new max will incorporate the previous min instead of the previous max. (For example, the least valid two-digit integer greater than or equal to 02 is 11, not 12.)
At the end, you return max, if it exists; otherwise, you return min, but prepending the least digit from your list.
For example, if this.allowedDigits is a collection of allowed digits, then we can write (in Java):
private Integer getAllowedDigitGreaterThanOrEqualTo(final int digit) {
for (int result = digit; result < 10; ++result) {
if (this.allowedDigits.contains(result)) {
return result;
}
}
// digit is bigger than anything in the list:
return null;
}
private int getAllowedNumberGreaterThanOrEqualTo(int n) {
int minResult = 0;
Integer maxResult = 0;
int powerOfTen = 1;
while (n > 0) {
final int digit = n % 10;
n /= 10;
minResult = getAllowedDigitGreaterThanOrEqualTo(0) * powerOfTen + minResult;
if (maxResult != null && this.allowedDigits.contains(digit)) {
maxResult = digit * powerOfTen + maxResult;
} else {
final Integer newDigit = getAllowedDigitGreaterThanOrEqualTo(digit + 1);
if (newDigit == null) {
maxResult = null;
} else {
maxResult = newDigit * powerOfTen + minResult;
}
}
powerOfTen *= 10;
}
if (maxResult == null) {
return getAllowedDigitGreaterThanOrEqualTo(1) * powerOfTen + minResult;
} else {
return maxResult;
}
}

How to pick top 5 values from a hash?

I have a hash of ids and their scores, it's something like this:
#objects = {1=>57, 4=>12, 3=>9, 5=>3, 55=>47, 32=>39, 17=>27, 29=>97, 39=>58}
How can I pick the top five and drop the rest ?
I'm doing this:
#orderedObject = #objects.sort_by {|k,v| v}.reverse
=>[[29, 97], [39, 58], [1, 57], [55, 47], [32, 39], [17, 27], [4, 12], [3, 9], [5, 3]]
Then I do this:
only Keys of the #orderedObjects:
#keys = #orderedObject.map { |key, value| key }
which gives me:
=>[29, 39, 1, 55, 32, 17, 4, 3, 5]
ALL I need is [29, 39, 1, 55, 32] the first 5 indexes. But I'm stuck I don't know how to do this.
You can do
#objects = {1=>57, 4=>12, 3=>9, 5=>3, 55=>47, 32=>39, 17=>27, 29=>97, 39=>58}
#objects.sort_by { |_, v| -v }[0..4].map(&:first)
# => [29, 39, 1, 55, 32]
#objects.sort_by { |_, v| -v }.first(5).map(&:first)
# => [29, 39, 1, 55, 32]
May i suggest this more verbose requires ruby > 1.9
Hash[#objects.sort_by{|k,v| -v}.first(5)].keys
A variant of Prof. Arup's answer:
objects = {1=>57, 4=>12, 3=>9, 5=>3, 55=>47, 32=>39, 17=>27, 29=>97, 39=>58}
objects.sort_by { |k,v| -v }.first(5).to_h.keys #=> [29, 39, 1, 55, 32]
Now suppose 3=>9 were instead 3=>39 and you wanted the keys corresponding to the top 5 values (which, in this case, would be 6 keys, as 39 is the fifth largest value, 3=>39 and 32=>39), you could first compute:
threshold = objects.values.sort.last(5).min #=> 39
If you wanted the keys to be ordered by the order of values threshold or larger,
objects.select { |_,v| v >= threshold }.sort_by { |_,v| -v }.map(&:first)
#=> [29, 39, 1, 55, 3, 32]
If you don't care about the order,
objects.select { |_,v| v >= threshold }.keys #=> [1, 3, 55, 32, 29, 39]

Splitting an array by performing an arithmetic function in ruby

I have an array in Ruby like [3,4,5] and I want to create sub-arrays by diving or multiplying. For example, I want to multiply each number in the array by 2, 3, and 4, returning [[6,9,12],[8,12,16],[10,15,20]]
After that, what's the best way to count the total number of units? In this example, it would be 9, while array.count would return 3.
Thanks
The simplest way I could think of was:
[3,4,5].map { |v|
[3,4,5].map { |w|
w * v
}
}
I'm sure there is a more elegant way.
As for the count you can use flatten to turn it into a single array containing all the elements.
[[9, 12, 15], [12, 16, 20], [15, 20, 25]].flatten
=> [9, 12, 15, 12, 16, 20, 15, 20, 25]
You might find it convenient to use matrix operations for this, particularly if it is one step among several involving matrices, vectors, and/or scalars.
Code
require 'matrix'
def doit(arr1, arr2)
(Matrix.column_vector(arr2) * Matrix.row_vector(arr1)).to_a
end
def nbr_elements(arr1, arr2) arr1.size * arr2.size end
Examples
arr1 = [3,4,5]
arr2 = [3,4,5]
doit(arr1, arr2)
#=> [[ 9, 12, 15],
# [12, 16, 20],
# [15, 20, 25]]
nbr_elements(arr1, arr2)
#=> 9
doit([1,2,3], [4,5,6,7])
#=> [[4, 8, 12],
# [5, 10, 15],
# [6, 12, 18],
# [7, 14, 21]]
nbr_elements([1,2,3], [4,5,6,7])
#=> 12
Alternative
If you don't want to use matrix operations, you could do it like this:
arr2.map { |e| [e].product(arr1).map { |e,f| e*f } }
Here's an example:
arr1 = [1,2,3]
arr2 = [4,5,6,7]
arr2.map { |e| [e].product(arr1).map { |e,f| e*f } }
#=> [[4, 8, 12],
# [5, 10, 15],
# [6, 12, 18],
# [7, 14, 21]]

Array select to get true and false arrays?

I know I can get this easily:
array = [45, 89, 23, 11, 102, 95]
lower_than_50 = array.select{ |n| n<50}
greater_than_50 = array.select{ |n| !n<50}
But is there a method (or an elegant manner) to get this by only running select once?
[lower_than_50, greater_than_50] = array.split_boolean{ |n| n<50}
over, under_or_equal = [45, 89, 23, 11, 102, 95].partition{|x| x>50 }
Or simply:
result = array.partition{|x| x>50 }
p result #=> [[89, 102, 95], [45, 23, 11]]
if you rather want the result as one array with two sub-arrays.
Edit: As a bonus, here is how you would to it if you have more than two alternatives and want to split the numbers:
my_custom_grouping = -> x do
case x
when 1..50 then :small
when 51..100 then :large
else :unclassified
end
end
p [-1,2,40,70,120].group_by(&my_custom_grouping) #=> {:unclassified=>[-1, 120], :small=>[2, 40], :large=>[70]}
The answer above is spot on!
Here is a general solution for more than two partitions (for example: <20, <50, >=50):
arr = [45, 89, 23, 11, 102, 95]
arr.group_by { |i| i < 20 ? 'a' : i < 50 ? 'b' : 'c' }.sort.map(&:last)
=> [[11], [45, 23], [89, 102, 95]]
This can be very useful if you're grouping by chunks (or any mathematically computable index such as modulo):
arr.group_by { |i| i / 50 }.sort.map(&:last)
=> [[45, 23, 11], [89, 95], [102]]

Every Other 2 Items in Array

I need a ruby formula to create an array of integers. The array must be every other 2 numbers as follows.
[2, 3, 6, 7, 10, 11, 14, 15, 18, 19...]
I have read a lot about how I can do every other number or multiples, but I am not sure of the best way to achieve what I need.
Here's an approach that works on any array.
def every_other_two arr
arr.select.with_index do |_, idx|
idx % 4 > 1
end
end
every_other_two((0...20).to_a) # => [2, 3, 6, 7, 10, 11, 14, 15, 18, 19]
# it works on any array
every_other_two %w{one two three four five six} # => ["three", "four"]
array = []
#Change 100000 to whatever is your upper limit
100000.times do |i|
array << i if i%4 > 1
end
This code works for any start number to any end limit
i = 3
j = 19
x =[]
(i...j).each do |y|
x << y if (y-i)%4<2
end
puts x
this should work
For fun, using lazy enumerables (requires Ruby 2.0 or gem enumerable-lazy):
(2..Float::INFINITY).step(4).lazy.map(&:to_i).flat_map { |x| [x, x+1] }.first(8)
#=> => [2, 3, 6, 7, 10, 11, 14, 15]
here's a solution that works with infinite streams:
enum = Enumerator.new do |y|
(2...1/0.0).each_slice(4) do |slice|
slice[0 .. 1].each { |n| y.yield(n) }
end
end
enum.first(10) #=> [2, 3, 6, 7, 10, 11, 14, 15, 18, 19]
enum.each do |n|
puts n
end
Single Liner:
(0..20).to_a.reduce([0,[]]){|(count,arr),ele| arr << ele if count%4 > 1;
[count+1,arr] }.last
Explanation:
Starts the reduce look with 0,[] in count,arr vars
Add current element to array if condition satisfied. Block returns increment and arr for the next iteration.
I agree though that it is not so much of a single liner though and a bit complex looking.
Here's a slightly more general version of Sergio's fine answer
module Enumerable
def every_other(slice=1)
mod = slice*2
res = select.with_index { |_, i| i % mod >= slice }
block_given? ? res.map{|x| yield(x)} : res
end
end
irb> (0...20).every_other
=> [1, 3, 5, 7, 9, 11, 13, 15, 17, 19]
irb> (0...20).every_other(2)
=> [2, 3, 6, 7, 10, 11, 14, 15, 18, 19]
irb> (0...20).every_other(3)
=> [3, 4, 5, 9, 10, 11, 15, 16, 17]
irb> (0...20).every_other(5) {|v| v*10 }
=> [50, 60, 70, 80, 90, 150, 160, 170, 180, 190]

Resources