Related
list = [5, 10, 20, 40, 50, 42, 35, 26, 18]
So in this example, I don't want an element to exceed the value 40 and if it does, I want the element to have a value of 40, e.g. the element with the value 50 will become 40.
list.map! { |i| i > 40 ? 40 : i }
=> [5, 10, 20, 40, 40, 40, 35, 26, 18]
map method permits you to apply a transformation to all the elements of your collection so I think fits perfectly in this case.
Or, if you are populating your array one element at a time, you could insert the real value just if it's 40 or less, 40 otherwise.
If 40 is the max, you need the min from 40 and the element ;)
list = [5, 10, 20, 40, 50, 42, 35, 26, 18]
list.map{ |v| [40, v].min }
# => [5, 10, 20, 40, 40, 40, 35, 26, 18]
If you're using Ruby 2.4 or newer, you can make use of Comparable#clamp:
list.map { |n| n.clamp(0, 40) }
# => [5, 10, 20, 40, 40, 40, 35, 26, 18]
Note that this will also fix the minimum value to 0. This may or may not be useful in your case, and only applies if all items are expected to be non-negative numbers.
I'm working with some lazy iteration, and would like to be able to specify a multiple step for this iteration. This means that I want the step to alternate between a and b. So, if I had this as a range (not lazy just for simplification)
(1..20).step(2, 4)
I would want my resulting range to be
1 # + 2 =
3 # + 4 =
7 # + 2 =
9 # + 4 =
13 # + 2 =
15 # + 4 =
19 # + 2 = 21 (out of range, STOP ITERATION)
However, I cannot figure out a way to do this. Is this at all possible in Ruby?
You could use a combination of cycle and Enumerator :
class Range
def multi_step(*steps)
a = min
Enumerator.new do |yielder|
steps.cycle do |step|
yielder << a
a += step
break if a > max
end
end
end
end
p (1..20).multi_step(2, 4).to_a
#=> [1, 3, 7, 9, 13, 15, 19]
Note that the first element is 1, because the first element of (1..20).step(2) is also 1.
It takes exclude_end? into account :
p (1...19).multi_step(2, 4).to_a
#=> [1, 3, 7, 9, 13, 15]
And can be lazy :
p (0..2).multi_step(1,-1).first(20)
#=> [0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1]
p (0..Float::INFINITY).multi_step(*(1..100).to_a).lazy.map{|x| x*2}.first(20)
#=> [0, 2, 6, 12, 20, 30, 42, 56, 72, 90, 110, 132, 156, 182, 210, 240, 272, 306, 342, 380]
Here's a variant of FizzBuzz, which generates all the multiples of 3 or 5 but not 15 :
p (3..50).multi_step(2,1,3,1,2,6).to_a
#=> [3, 5, 6, 9, 10, 12, 18, 20, 21, 24, 25, 27, 33, 35, 36, 39, 40, 42, 48, 50]
Ruby doesn't have a built-in method for stepping with multiple values. However, if you don't actually need a lazy method, you can use Enumerable#cycle with an accumulator. For example:
range = 1..20
accum = range.min
[2, 4].cycle(range.max) { |step| accum += step; puts accum }
Alternatively, you could construct your own lazy enumerator with Enumerator::Lazy. That seems like overkill for the given example, but may be useful if you have an extremely large Range object.
I got this question in an interview and got almost all the way to the answer but got stuck on the last part. If I want to get the multiplication table for 5, for instance, I want to get the output to be formatted like so:
1, 2, 3, 4, 5
2, 4, 6, 8, 10
3, 6, 9, 12, 15
4, 8, 12, 16, 20
5, 10, 15, 20, 25
My answer to this is:
def make_table(n)
s = ""
1.upto(n).each do |i|
1.upto(n).each do |j|
s += (i*j).to_s
end
s += "\n"
end
p s
end
But the output for make_table(5) is:
"12345\n246810\n3691215\n48121620\n510152025\n"
I've tried variations with array but I'm getting similar output.
What am I missing or how should I think about the last part of the problem?
You can use map and join to get a String in one line :
n = 5
puts (1..n).map { |x| (1..n).map { |y| x * y }.join(', ') }.join("\n")
It iterates over rows (x=1, x=2, ...). For each row, it iterates over cells (y=1, y=2, ...) and calculates x*y. It joins every cells in a row with ,, and joins every rows in the table with a newline :
1, 2, 3, 4, 5
2, 4, 6, 8, 10
3, 6, 9, 12, 15
4, 8, 12, 16, 20
5, 10, 15, 20, 25
If you want to keep the commas aligned, you can use rjust :
puts (1..n).map { |x| (1..n).map { |y| (x * y).to_s.rjust(3) }.join(',') }.join("\n")
It outputs :
1, 2, 3, 4, 5
2, 4, 6, 8, 10
3, 6, 9, 12, 15
4, 8, 12, 16, 20
5, 10, 15, 20, 25
You could even go fancy and calculate the width of n**2 before aligning commas :
n = 11
width = Math.log10(n**2).ceil + 1
puts (1..n).map { |x| (1..n).map { |y| (x * y).to_s.rjust(width) }.join(',') }.join("\n")
It outputs :
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11
2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22
3, 6, 9, 12, 15, 18, 21, 24, 27, 30, 33
4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44
5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55
6, 12, 18, 24, 30, 36, 42, 48, 54, 60, 66
7, 14, 21, 28, 35, 42, 49, 56, 63, 70, 77
8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 88
9, 18, 27, 36, 45, 54, 63, 72, 81, 90, 99
10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110
11, 22, 33, 44, 55, 66, 77, 88, 99, 110, 121
Without spaces between the figures, the result is indeed unreadable. Have a look at the % operator, which formats strings and numbers. Instead of
s += (i*j).to_s
you could write
s += '%3d' % (i*j)
If you really want to get the output formatted in the way you explained in your posting (which I don't find that much readable), you could do a
s += "#{i*j}, "
This leaves you with two extra characters at the end of the line, which you have to remove. An alternative would be to use an array. Instead of the inner loop, you would have then something like
s += 1.upto(n).to_a.map {|j| i*j}.join(', ') + "\n"
You don't need to construct a string if you're only interested in printing the table and not returning the table(as a string).
(1..n).each do |a|
(1..n-1).each { |b| print "#{a * b}, " }
puts a * n
end
This is how I'd do it.
require 'matrix'
n = 5
puts Matrix.build(n) { |i,j| (i+1)*(j+1) }.to_a.map { |row| row.join(', ') }
1, 2, 3, 4, 5
2, 4, 6, 8, 10
3, 6, 9, 12, 15
4, 8, 12, 16, 20
5, 10, 15, 20, 25
See Matrix::build.
You can make it much shorter but here's my version.
range = Array(1..12)
range.each do |element|
range.map { |item| print "#{element * item} " } && puts
end
I thought I knew how FromDigits works, but it's doing something crazy now.
n[[990;;]]
FromDigits[n[[990;;]]]
outputs:
{9, 50, 0, 50, 1, 50, 2, 50, 3, 50, 4, 50, 5, 50, 6, 50, 7, 50, 8, 50, 9}
1405060708091011121309
instead of, you know, 950050150...
what's going on?
Documentation says that
FromDigits : constructs an integer from the list of its decimal digits.
So each number in the array must be less that 10 (decimal digits) for a simple concatenation.
Digits larger than the base are "carried": For example
FromDigits[{7, 11, 0, 0, 0, 122}] will give 810122
For more information go to http://reference.wolfram.com/language/ref/FromDigits.html
I think "string hacking" might be what you are asking for. This
myn = {9, 50, 0, 50, 1, 50, 2, 50, 3, 50, 4, 50, 5, 50, 6, 50, 7, 50, 8, 50, 9};
ToExpression[StringReplace[ToString[myn], ", " -> ""]][[1]]
gives you this integer
9500501502503504505506507508509
That turns your list into a string, replaces each comma space separator with nothing, turns that resulting string back into an integer and discards the now unneeded curly brackets.
A couple other ways..
FromDigits#Flatten#IntegerDigits#
{9, 50, 0, 50, 1, 50, 2, 50, 3, 50, 4, 50, 5, 50, 6, 50, 7, 50, 8, 50, 9}
9500501502503504505506507508509
(ToString /# # // StringJoin // ToExpression) &#
{9, 50, 0, 50, 1, 50, 2, 50, 3, 50, 4, 50, 5, 50, 6, 50, 7, 50, 8, 50, 9}
9500501502503504505506507508509
Say I have an array that represents a set of points:
x = [2, 5, 8, 33, 58]
How do I generate an array of all the pairwise distances?
x = [2, 5, 8, 33, 58]
print x.collect {|n| x.collect {|i| (n-i).abs}}.flatten
I think that would do it.
x.map{|i| x.map{|j| (i-j).abs } }
gives
[[0, 3, 6, 31, 56],
[3, 0, 3, 28, 53],
[6, 3, 0, 25, 50],
[31, 28, 25, 0, 25],
[56, 53, 50, 25, 0]]
(format it like this by printing it with 'pp' instead of puts)
and
x.map{|i| x.map{|j| (i-j).abs } }.flatten
gives
[0, 3, 6, 31, 56, 3, 0, 3, 28, 53, 6, 3, 0, 25, 50, 31, 28, 25, 0, 25, 56, 53, 50, 25, 0]
if you really want an array
If you really do want an array instead of a matrix, this is O(n^2/2) instead of O(n^2).
result=[]
x.each_index{|i| (i+1).upto(x.size-1){|j| result<<(x[i]-x[j]).abs}}