Inverting an array of arrays (matrix) in ruby - ruby

I have "text" which is an array of arrays, let's say:
1 2 3
4 5 6
7 8 9
and I just want to create another array of arrays but like this:
1 4 7
2 5 8
3 6 9
I cant get it working. It says: undefined method '[]=' for nil:NilClass
vect = Array.new()
3.times{|i|
3.times{|j|
vect[j][i] = text[i][j]
}
}

"text" is not a very good name for an array of arrays containing integers. That said, you might want to look into array.transpose.

You declare an empty array, but you don't fill it in with empty arrays.
Because the array you are using is empty, vect[j] will always return nil and not an array as you expect.
Here is the corrected code:
vect = [[], [], [], []]
4.times do |i|
4.times do |j|
vect[j][i] = text[i][j]
end
end

You can also you the Matrix class for those purposes, for instance:
require 'matrix'
m1 = Matrix[[1,2,3], [4,5,6],[7,8,9]]
m1.to_a.each {|r| puts r.inspect} #=> This is just print the matrix in that format.
[1, 2, 3]
[4, 5, 6]
[7, 8, 9]
- Transposed Version -
m1.transpose.to_a.each {|r| puts r.inspect} #=> Note the method `transpose` called. The rest is just for printin.
[1, 4, 7]
[2, 5, 8]
[3, 6, 9]

Related

Arithmetic sequence Ruby

It is a code to find the missing sequence of an arithmetic sequence and finding common difference and also checking is it is an increasing or decreasing sequence. Take user input for further operation
For Ex: enter array elements
2 4 6 10 12 14
missing number is 8 instead of
enter array elements
2
4
6
10
12
14
missing number is 8
puts "enter arithmetic sequence"
o = Array.new
x = gets.chomp
item = x.split(" ")
o.push(item)
puts "#{o}"
len = o.length
sum = (len + 1) * (o[0] + o[len - 1]) / 2
summ = 0
o.each { |a| summ+=a }
res = sum - summ
if(o[1]>o[0])
puts "its an increasing sequence"
else
puts "its a decreasing sequence"
end
common_difference = o[1] - o[0]
puts "Common difference is #{common_difference}"
puts "missing number is #{res}"
The operations like sum common difference are working, but requirement is that we need to take user input in a single line instead of taking in multiple line, split that and store in an array.
For taking sum I used actual sum - target sum method.
Main issue is that it rise an error
`*': Array can't be coerced into Integer
How to convert array elements that is in string format to int using to_i method or Integer method
Expected Output
i/p 2 4 6 8 12 14
o/p
missing number 10
requirement is that we need to take user input in a single line instead of taking in multiple line, split that and store in an array
gets.chomp returns a string with trailing newline removed, e.g. (the 2nd line being user input)
x = gets.chomp
2 4 6 8 12 14
x #=> "2 4 6 8 12 14"
split converts that string to an array:
x.split
#=> ["2", "4", "6", "8", "12", "14"]
what's missing is the conversion to integer. To convert each element of an array, there's map:
x.split.map { |s| s.to_i }
#=> => [2, 4, 6, 8, 12, 14]
or its short-hand notation:
x.split.map(&:to_i)
#=> => [2, 4, 6, 8, 12, 14]
applied to your code:
puts "enter arithmetic sequence"
x = gets.chomp
o = x.split.map(&:to_i)
puts "#{o}"
# ...
Note that there's no need to create an empty array. You can just assign the result of map to o.
The rest of your code seems to work as expected. But you should check out Cary Swoveland's answer for more succinct way of finding the missing element.
Try this:
def missing_number(arr)
((arr.size + 1) * (arr.first + arr.last))/2 - arr.sum
end
missing_number [2, 4, 6, 10, 12, 14] #=> 8
missing_number [11, 8, 5, 2, -4, -7] #=> -1
missing_number [1.2, 2.0, 2.4, 2.8, 3.2] #=> 1.6000000000000014
Suppose arr were not missing any values. For example,
arr = [2, 4, 6, 8, 10, 12, 14]
Then:
arr.sum
#=> 56
which, because it is an arithmetic series, we could alternatively compute as follows:
(arr.size * (arr.first + arr.last))/2
#=> 56
In fact,
arr = [2, 4, 6, 10, 12, 14]
and
arr.sum
#=> 48
As I explained above, we can calculate the sum of the values of arr after the missing value has been inserted as follows:
((arr.size + 1) * (arr.first + arr.last))/2
#=> 56
The missing value therefore equals 56 - 48 #=> 8.
Here is another way to find the missing value that is slightly less efficient.
def missing_number(arr)
arr.each_cons(2).max_by { |a,b| (b-a).abs }.sum/2
end
missing_number [2, 4, 6, 10, 12, 14] #=> 8
missing_number [11, 8, 5, 2, -4, -7] #=> -1
missing_number [1.2, 2.0, 2.4, 2.8, 3.2] #=> 1.6
Suppose
arr = [11, 8, 5, 2, -4, -7]
The steps are as follows.
enum = arr.each_cons(2)
#=> #<Enumerator: [11, 8, 5, 2, -4, -7]:each_cons(2)>
We can see the (5) values that the enumerator will generate and pass to Enumerable#max_by by converting enum to an array:
enum.to_a
#=> [[11, 8], [8, 5], [5, 2], [2, -4], [-4, -7]]
Next let's look at the values that max_by will compare:
enum.map { |a,b| (b-a).abs }
#=> [3, 3, 3, 6, 3]
We therefore obtain the following:
c = enum.max_by { |a,b| (b-a).abs }
#=> [2, -4]
The last two steps calculate the average of 2 and -4:
d = c.sum
#=> -2
d/2
#=> -1

How to handle negative iterator passed in function?

I am working on a manual rotate function in Ruby. But I ran into issue there are negative offsets passed in some examples. Is it possible to iterate from a negative number up to a specified index(not sure what that index would be)?
def my_rotate(arr, offset=1)
if offset < 1
for i in offset
arr.push(arr.shift)
end
else
for i in 1..offset
arr.push(arr.shift)
end
end
arr
end
Following with your code, you can use Array#pop and Array#unshift (which are the opposites of Array#push and Array#shift):
def my_rotate(array, offset=1)
arr = array.dup
if offset < 1
for i in 1..offset.abs
arr.unshift(arr.pop)
end
else
for i in 1..offset
arr.push(arr.shift)
end
end
arr
end
Notice the change in line 5 for i in 1..offset.abs to be able to loop the array, and the addition of line 2 arr = array.dup to prevent the original array from being mutated.
This is pretty much how Array#rotate does it (in C).
Code
class Array
def my_rotate(n=1)
n %= self.size
self[n..-1].concat(self[0,n])
end
end
Examples
arr = [1,2,3,4]
arr.my_rotate 0 #=> [1,2,3,4]
arr.my_rotate #=> [2, 3, 4, 1]
arr.my_rotate 1 #=> [2, 3, 4, 1]
arr.my_rotate 4 #=> [1, 2, 3, 4]
arr.my_rotate 5 #=> [2, 3, 4, 1]
arr.my_rotate 9 #=> [2, 3, 4, 1]
arr.my_rotate -1 #=> [4, 1, 2, 3]
arr.my_rotate -4 #=> [1, 2, 3, 4]
arr.my_rotate -5 #=> [4, 1, 2, 3]
arr.my_rotate -9 #=> [4, 1, 2, 3]
Explanation
The line
n %= self.size
which Ruby's parser expands to
n = n % self.size
converts n to an integer between 0 and self.size - 1. Moreover, it does so for both positive and negative values of n.
The line
self[n..-1].concat(self[0,n])
appends the first n elements of arr to an array comprised of the last arr.size - n elements of arr. The resulting array is then returned by the method.
If you do not wish to add this method to the class Array you could of course define it def my_rotate(arr, n)....

Find all max of elements of an array [duplicate]

This question already has answers here:
Returning all maximum or minimum values that can be multiple
(3 answers)
Closed 8 years ago.
Suppose I have a array, namely arr: [1, 2, 3, 4, 8, 8], and I want to find all max elements in this array:
arr.allmax # => [8, 8]
Is there a built-in method combinations to solve this? I don't like to monkey patch as I am doing now:
class Array
def allmax
max = self.max
self.select { |e| e == max }
end
end
Monkey patch is not a good idea, I could just do:
some_array.select { |e| e == some_array.max }
and it will work as allmax. Thanks for all answers and comments for inspirations.
Here's a fun way to do it.
arr.sort!.slice arr.index(arr[-1]) || 0..-1
Sort the array, then find the leftmost index of the array which matches the rightmost index of the array, and take the subslice that matches that range (or the range 0..-1 if the array is empty).
This one is kind of fun in that it requires no intermediate arrays, though it does mutate the input to achieve the one-liner.
Here is one way :
2.1.0 :006 > arr = [1, 2, 3, 4, 8, 8]
=> [1, 2, 3, 4, 8, 8]
2.1.0 :007 > arr.group_by { |i| i }.max.last
=> [8, 8]
2.1.0 :008 >
Here is a method :-
def all_max(arr)
return [] if arr.empty?
arr.group_by { |i| i }.max.last
end
Another way:
def all_max(arr)
return [] if arr.empty?
mx = arr.max
[mx] * arr.count { |e| e == mx }
end
all_max([1, 2, 3, 4, 8, 8])
#=> [8, 8]
To construct the array in a single pass, you could do this:
arr.each_with_object([]) do |e,a|
if a.empty?
a << e
else
case e <=> a.first
when 0 then a << e
when 1 then a.replace([e])
end
end
end

How to drop the end of an array in Ruby

Array#drop removes the first n elements of an array. What is a good way to remove the last m elements of an array? Alternately, what is a good way to keep the middle elements of an array (greater than n, less than m)?
This is exactly what Array#pop is for:
x = [1,2,3]
x.pop(2) # => [2,3]
x # => [1]
You can also use Array#slice method, e.g.:
[1,2,3,4,5,6].slice(1..4) # => [2, 3, 4, 5]
or
a = [1,2,3,4,5,6]
a.take 3 # => [1, 2, 3]
a.first 3 # => [1, 2, 3]
a.first a.size - 1 # to get rid of the last one
The most direct opposite of drop (drop the first n elements) would be take, which keeps the first n elements (there's also take_while which is analogous to drop_while).
Slice allows you to return a subset of the array either by specifying a range or an offset and a length. Array#[] behaves the same when passed a range as an argument or when passed 2 numbers
this will get rid of last n elements:
a = [1,2,3,4,5,6]
n = 4
p a[0, (a.size-n)]
#=> [1, 2]
n = 2
p a[0, (a.size-n)]
#=> [1, 2, 3, 4]
regard "middle" elements:
min, max = 2, 5
p a.select {|v| (min..max).include? v }
#=> [2, 3, 4, 5]
I wanted the return value to be the array without the dropped elements. I found a couple solutions here to be okay:
count = 2
[1, 2, 3, 4, 5].slice 0..-(count + 1) # => [1, 2, 3]
[1, 2, 3, 4, 5].tap { |a| a.pop count } # => [1, 2, 3]
But I found another solution to be more readable if the order of the array isn't important (in my case I was deleting files):
count = 2
[1, 2, 3, 4, 5].reverse.drop count # => [3, 2, 1]
You could tack another .reverse on there if you need to preserve order but I think I prefer the tap solution at that point.
You can achieve the same as Array#pop in a non destructive way, and without needing to know the lenght of the array:
a = [1, 2, 3, 4, 5, 6]
b = a[0..-2]
# => [1, 2, 3, 4, 5]
n = 3 # if we want drop the last n elements
c = a[0..-(n+1)]
# => [1, 2, 3]
Array#delete_at() is the simplest way to delete the last element of an array, as so
arr = [1,2,3,4,5,6]
arr.delete_at(-1)
p arr # => [1,2,3,4,5]
For deleting a segment, or segments, of an array use methods in the other answers.
You can also add some methods
class Array
# Using slice
def cut(n)
slice(0..-n-1)
end
# Using pop
def cut2(n)
dup.tap{|x| x.pop(n)}
end
# Using take
def cut3(n)
length - n >=0 ? take(length - n) : []
end
end
[1,2,3,4,5].cut(2)
=> [1, 2, 3]

How do I check an array for duplicates? [duplicate]

This question already has answers here:
How to find and return a duplicate value in array
(23 answers)
Closed 8 years ago.
I've got an array A. I'd like to check if it contains duplicate values. How would I do so?
Just call uniq on it (which returns a new array without duplicates) and see whether the uniqed array has less elements than the original:
if a.uniq.length == a.length
puts "a does not contain duplicates"
else
puts "a does contain duplicates"
end
Note that the objects in the array need to respond to hash and eql? in a meaningful for uniq to work properly.
In order to find the duplicated elements, I use this approach (with Ruby 1.9.3):
array = [1, 2, 1, 3, 5, 4, 5, 5]
=> [1, 2, 1, 3, 5, 4, 5, 5]
dup = array.select{|element| array.count(element) > 1 }
=> [1, 1, 5, 5, 5]
dup.uniq
=> [1, 5]
If you want to return the duplicates, you can do this:
dups = [1,1,1,2,2,3].group_by{|e| e}.keep_if{|_, e| e.length > 1}
# => {1=>[1, 1, 1], 2=>[2, 2]}
If you want just the values:
dups.keys
# => [1, 2]
If you want the number of duplicates:
dups.map{|k, v| {k => v.length}}
# => [{1=>3}, {2=>2}]
Might want to monkeypatch Array if using this more than once:
class Array
def uniq?
self.length == self.uniq.length
end
end
Then:
irb(main):018:0> [1,2].uniq?
=> true
irb(main):019:0> [2,2].uniq?
=> false

Resources