I created a sample ruby program to swap elements in an array
class Swap
def swp(a,b)
self[a],self[b] = self[b],self[a]
self
end
array = [1,2,3]
array.swp(1,2)
puts array
end
I am getting the following error
NoMethodError: private method `swp' called for [1, 2, 3]:Array
from (irb):77:in `<class:Swap>'
from (irb):71
from /home/rahulv/.rvm/gems/ruby-2.0.0-p481/gems/railties-3.2.16/lib/rails/commands/console.rb:47:in `start'
from /home/rahulv/.rvm/gems/ruby-2.0.0-p481/gems/railties-3.2.16/lib/rails/commands/console.rb:8:in `start'
from /home/rahulv/.rvm/gems/ruby-2.0.0-p481/gems/railties-3.2.16/lib/rails/commands.rb:41:in `<top (required)>'
from script/rails:6:in `require'
from script/rails:6:in `<main>'
Please help to fix it.
UPDATE
I tried the same program with dynamic array input like this:
class Swap
def swp(a,b)
self[a],self[b] = self[b],self[a]
self
end
end
puts "enter the array elements "
input = gets.chomp
ary = []
while input != 'fin'
ary << input.to_i
input = gets.chomp
end
puts ary
puts "enter the elements to be swapped"
a=gets
b=gets
s=Swap.new
ary = ary.s.swp(a,b)
puts ary
Now the output error is like this:
enter the array elements
1
2
3
4
5
fin
enter the positions to be swapped
1
2
NoMethodError: private method `s' called for [0, 1, 2, 3, 4, 5]:Array
from (irb):17:in `<class:Swap>'
from (irb):1
from /home/rahulv/.rvm/gems/ruby-2.0.0-p481/gems/railties-3.2.16/lib/rails/commands/console.rb:47:in `start'
array.class = Array, you should add swp method for Array class.
class Array
def swp(a,b)
self[a],self[b] = self[b],self[a]
self
end
end
array = [1,2,3]
array.swp(0,1) #The array index start from 0, not 1
puts array.inspect
=> [2, 1, 3]
Update:
class Array
def swp(a,b)
self[a],self[b] = self[b],self[a]
self
end
end
puts "enter the array elements "
ary = []
input = 0
while 1
input = gets.chomp
if input != 'fin'
ary << input.to_i
else
break
end
end
puts "enter the positions to be swapped"
a=gets.to_i
b=gets.to_i
ary.swp(a,b)
puts ary.inspect
I don't like editing classes like that, for example if there's another class in the ancestor tree that implements the actual swp method (for any reason) and you implemented yours, and you try to use the actual documented one, you'll find unexplained behaviour, and it might be uneasy to figure out why it's behaving like that, beacuse your method is hiding, it's more maintainable if you add your methods to the ancestry tree using a module and then including it to the class.
module Swappable
def swp(a, b)
# method goes here
end
end
Then in another file you would do
class Array
include Swappable
end
This way when you call Array.ancestors you'd see your module
Array.ancestors
=> [Array, Swappable, ....]
And when you try something like
Array.instance_method(:swp).owner
you'll get Swappable, while an open class editing would return Array
This is just my oppinion on this matter, you can pick whatever works for you.
You can try the following code blog for take input an array and swap with two positions.
Here I initialize Swap class with an input array and then pass two swap position.
Main Class
class Swap
def initialize(array)
#array = array#[1,2,3,4,5]
end
def swp(a,b)
#array[a],#array[b] = #array[b],#array[a]
#array
end
end
Take Input for array
puts "ArrayInput :: Enter numbers separated by spaces, press 'Enter' to finish:"
array = gets
array = array.split(" ")
Take Input for swap positions
puts "SwapInput:: For FirstPosition, press 'Enter' to finish:"
first_position = gets.to_i
puts "SwapInput:: For SecondPosition, press 'Enter' to finish:"
second_position = gets.to_i
Initialize Swap Class
swap = Swap.new(array)
array = swap.swp(first_position, second_position)
puts "Array after swap:"
puts array
Related
I am trying to iterate through a folder, select all the files that end in .bowtie.txt, count the number of lines, and then write the number of lines with the filename it came from, to a hash (or even better an external csv but a hash will do for now). I was provided with this solution
Dir['/Volumes/.../*.bowtie.txt'].inject({}) do |memo, file|
memo[file] = File.readlines(file).select do |line|
line =~ /^[0-9]+\s*(\+|\-)/ # only those, matching
end.count
puts memo
end
however this has to odd behaviour of selecting a file, then giving me one hash before it fails as follows:
Me:~ me$ ruby /Users/me/Desktop/SequencingScripts/Plots/GeneralScripts/DistinctPositions.rb
{"/Volumes/SeagateBackupPlusDriv/SequencingRawFiles/TumourOesophagealOCCAMS/SequencingScripts/3finalcounts/SLX-9279.GoodDysplasia.FSeqA_BEST2_NEW_0204_LessThan10PCent_HGD_.fq.gz.bowtie.txt"=>31312}
/Users/me/Desktop/SequencingScripts/Plots/GeneralScripts/DistinctPositions.rb:5:in `block in <main>': undefined method `[]=' for nil:NilClass (NoMethodError)
from /Users/me/Desktop/SequencingScripts/Plots/GeneralScripts/DistinctPositions.rb:4:in `each'
from /Users/me/Desktop/SequencingScripts/Plots/GeneralScripts/DistinctPositions.rb:4:in `inject'
from /Users/me/Desktop/SequencingScripts/Plots/GeneralScripts/DistinctPositions.rb:4:in `<main>'
when I don't use puts memo I don't get an error but I also don't get any output to the terminal. How do I get what I want?
In order to use inject in this context, you need to return your memo object at the end. So in your example, that would look like:
Dir['/Volumes/.../*.bowtie.txt'].inject({}) do |memo, file|
memo[file] = File.readlines(file).select do |line|
line =~ /^[0-9]+\s*(\+|\-)/ # only those, matching
end.count
puts memo
memo
end
Here's a contrived example to illustrate the same error & resolution:
[1] pry(main)> [1, 2, 3].inject({}) { |hash, num| hash[num] = 1 }
NoMethodError: undefined method []= for 1:Fixnum
[2] pry(main)> [1, 2, 3].inject({}) { |hash, num| hash[num] = 1; hash }
=> {1=>1, 2=>1, 3=>1}
if you use inject your block should ALWAYS return updated memo in the last line. In your case during the second iteration memo is equal to last line so to the result of puts memo
Dir['/Volumes/.../*.bowtie.txt'].inject({}) do |memo, file|
memo[file] = File.readlines(file).select do |line|
line =~ /^[0-9]+\s*(\+|\-)/ # only those, matching
end.count
puts memo
memo
end
I'm trying to write quicksort in Ruby, but I get an error that says:
qsort.rb:43:in `<': comparison of Fixnum with nil failed (ArgumentError)
from qsort.rb:43:in `block in dist'
from qsort.rb:42:in `each'
from qsort.rb:42:in `dist'
from qsort.rb:32:in `sort'
from qsort.rb:34:in `sort'
from qsort.rb:53:in `<main>'
This is my code:
#!usr/bin/ruby
class QArray
#data = []
#pvalue
#less
#more
def initialize(arr = [])
#data = arr
#pvalue = #data[0] unless #data.empty?
end
#these methods are so I can treat a QArray like a regular array
def push(value)
#data.push value
end
def empty?
#data.empty?
end
def single?
return #data.size == 1
end
def print
puts #data
end
def sort
puts "starting the sort with an array of #{#data}"
dist unless #data.empty?
#less.sort unless #less.empty? || #less.single?
#more.sort unless #more.empty? || #more.single?
#data = #less + #more #combine the two arrays again
end
def dist
#distributes values into subarrays
#less = QArray.new
#more = QArray.new
#data.each {|e|
if (e < #pvalue)
#less.push e
else #includes both equals and greater than
#more.push e
end
}
end
end
arr = QArray.new ([1,5,6,7,9,23,43,2,4,6])
arr.sort
arr.print
I'm guessing that this is related to e being nil in the block. However, this shouldn't happen, because I check whether the array is empty before I call dist.
Why do I get this error, and what can I do to fix it?
You create new QArrays in dist.
You initialize #pvalue on QArray creation, but they're empty when created in dist.
In dist you then try to use #pvalue, which is nil, because you create the array empty and only then add values to it, never updating the uninitialized #pvalue value.
Unrelated, but what are those class instance variables at the top of QArray for?!
I'm the new of the ruby code. My team member write a class Deck which implement the game set
class Deck
#array = Array.new
# create a deck of n cards
# n <= 0 returns empty array.
def initialize (n=1)
#array = (0..n-1).to_a
end
end
im trying to write rspec testing which is also new to us, here's the test code:
#!/user/bin/ruby -w
require '../deck'
require 'rspec/expectations'
describe "Deck#new" do
context "with one parameter " do
it "has parameter n = 0" do
expect(Deck.new(0)).to match_array([])
end
it "has parameter n = 1" do
expect(Deck.new(1)).to eq([0])
end
it "has parameter n = 5" do
expect(Deck.new(5))==([0,1,2,3,4])
end
it "has parameter n<0" do
expect(Deck.new(-1))==([])
end
end
end
but when i run this test, it gives me
expected a collection that can be converted to an array with `#to_ary` or `#to_a`, but got #<Deck:0xb82edb74 #array=[]>
and the first two failed, which I don't understand. Did I miss something in my code? Thanks for help. My rspec version is the newest.
You need a method to access the cards:
class Deck
def initialize (n=1)
#array = (0..n-1).to_a
end
def cards
#array
end
end
In this way:
Deck.new(5).cards
#=> [0, 1, 2, 3, 4]
So, change your tests to:
it "has parameter n = 0" do
expect(Deck.new(0).cards).to match_array([])
end
and so on...
UPDATE:
Deck.new(n) returns the whole object
Deck.new(5)
=> #<Deck:0x007fb56b0e82b0 #array=[0, 1, 2, 3, 4]>
For this reason your test will fail... The whole object is not the same as the content of #array ([0, 1, 2, 3, 4]).
UPDATE 2:
You can define any new method, for example the number os cards in a deck:
class Deck
def initialize (n=1)
#array = (0..n-1).to_a
end
def cards
#array
end
def number_of_cards
#array.size
end
end
Deck.new(5).number_of_cards
#=> 5
The spec:
# spec/row_spec.rb
require "spec_helper"
module Mastermind
describe Row do
context "#initialize" do
it "has four elements by default" do
row = Row.new
expect(row.values.size).to eq 4
end
it "can only go up to 6" do
row = Row.new
expect(row.values.max).to be <= 6
end
end
end
end
The code:
# lib/mastermind/row.rb
module Mastermind
class Row
attr_accessor :values
def initialize (values=random_row)
#values = values
end
def random_row
4.times {random||=[] << rand(1..6)}
end
end
end
Row is supposed to be a row for a game of mastermind, with four random values between 1 and 6, and this test is supposed to make sure it is functioning properly. It looks like values is returning an int instead of an array. Why?
How would I troubleshoot this on my own? I tried to make something simple to see exactly what was happening with values by appending
row = Row.new
puts row.values
to my row.rb, but I just get an uninitialized constant error. Why doesn't this work?
This is your problem (random_row):
[1] pry(main)> 4.times {random||=[] << rand(1..6)}
=> 4
times returns the value. You want something like this:
[2] pry(main)> 4.times.map { rand(1..6) }
=> [6, 5, 3, 6]
Your other issue is because you didn't specify the module, Row doesn't exist, Mastermind::Row does.
[4] pry(main)> row = Mastermind::Row.new
=> #<Mastermind::Row:0x00000101c593e0 #values=4>
[5] pry(main)> row.values
=> 4
Your issue is that #random_row will return 4 (the return value of Fixnum#times is self), which means that when you initialize the Row, #values is set to 4.
You probably want something like:
def random_row
Array.new(4) { rand(1..6) }
end
I am currently working on a basic Ruby programming project, that focuses on creating classes, and operations on those classes. I have very little experience, but understand the general idea of Ruby.
My task is making an Array2 class. Creating arrays from the class, perform operations on the arrays. The methods I attempted are a to-string method, and a is-reverse method that has two array parameters, and tests if the first array is the reverse of the second array.
Here is my attempt, I tried but I am having trouble passing the arrays properly into the class. Also I believe that I am having some calling complications.
class Array2
def initialize (a)
#array = Array.new(a)
end
def to_s
return #array
end
def isreverse (array1,array2)
reverasea = Array.new
reverasea = array1.reverse
if (reversea = array2) then
return "The First Array Is The Reverse Of The Second Array"
else
return "The First Array Is Not The Reverse Of The Second Array"
end
end
end
array1 = ["4","5","6","7"]
array2 = ["7","6","5","3"]
a1 = Array2.new(array1)
a2 = Array2.new(array2)
puts a1.to_s
puts a2.to_s
puts a1.isreverse(array1, array2)
You have an assignment where you probably meant equality test:
if (reversea = array2) then
you could dispense with reversea entirely and just test (this requires a reverse method in Array2)
if (array1.reverse == #array) then
I would personally make isreverse a boolean, and eliminate the need to pass in the same array again:
def isreverse? (array1)
return (#array.reverse == array1)
end
then use it like
puts "The First Array Is#{a1.isreverse?(a2)?"":" Not"} The Reverse Of The Second Array"
put it all together and it looks like:
class Array2
def initialize (a)
#array = Array.new(a)
end
def to_s
return #array
end
def reverse
#array.reverse
end
def isreverse? (array1)
return (array1.reverse == #array)
end
end
array1 = ["4","5","6","7"]
array2 = ["7","6","5","3"]
a1 = Array2.new(array1)
a2 = Array2.new(array2)
puts a1.to_s
puts a2.to_s
puts "The First Array Is#{a1.isreverse?(a2)?"":" Not"} The Reverse Of The Second Array"
fiddle
Here are some adjustments to your existing approach. I put in comments where I changed the original::
class Array2
def initialize (a)
#array = Array.new(a)
end
def to_array # to_s is a misnomer: it doesn't return a string
return #array
end
def isreverse (a)
#reverasea = Array.new NOTE this is not needed; the following .reverse creates a new array for you
reversea = a.to_array.reverse # get the reverse of the array represented
# NOTE = is assign, == is compare in this case
# The following compares the reversed of the array `a` with the array value of this class, #array
if (reversea == #array) then
return "The First Array Is The Reverse Of The Second Array"
else
return "The First Array Is Not The Reverse Of The Second Array"
end
end
end
array1 = ["4","5","6","7"]
array2 = ["7","6","5","3"]
a1 = Array2.new(array1)
a2 = Array2.new(array2)
puts a1.to_array # (renamed)
puts a2.to_array # (renamed)
#puts a1.isreverse(array1, array2) NOTE you don't need to pass array1 into class a1 since it is already made from array1
puts a1.isreverse(a2)
I would go for something simpler such as:
Filename: reverser.rb
class Reverser
def self.is_reverse_of(array1,array2)
array1_reversed=array1.reverse
is_or_isnt= (array1_reversed==array2)? 'Not ' : ''
return "The First Array Is #{is_or_isnt}The Reverse Of The Second Array"
end
end
puts Reverser.is_reverse_of(["4","5","6","7"], ["7","6","5","4"])
puts Reverser.is_reverse_of(["4","5","6","7"], ["7","6","5","3"])
ruby reverser.rb
The First Array Is Not The Reverse Of The Second Array
The First Array Is The Reverse Of The Second Array
The idea being to use a class level method and not instantiate as much and have less code.