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
Related
def key_for_min_value(name_hash)
name_hash.max_by {|k, v| 0-v}[0]
end
This was my code to fulfill the test suite for finding the lowest value of a hash (this was for one of my lessons online).
I know there are much easier ways to do this but I had some restrictions, as you can see below:
**A Few Restrictions:
We want you to build this on your own. Some of the following methods are helpful but off limits for this exercise. (We'll cover a few below in more depth in subsequent lessons).
I could not use keys, values, min, sort, min_by to make it pass.
This code returned the key with the lowest value (a hash of key ==> integers) but here was the requirement I could not figure out.
If the method is called and passed an argument of an empty hash, it should return nil.
Only first month programming, so this may be obvious but is there a way to return nil for an empty hash, and keep my existing code intact?
Thanks for your help
To a beginner programmer I would recommend to print all intermediate results of expressions, or work in IRB.
def key_for_min_value(name_hash)
puts
puts "in key_for_min_value with parameter #{name_hash}"
# puts "about to return nil" if name_hash.empty?
# return nil if name_hash.empty?
name_hash.max_by { | item | puts "item=#{item}" }
max = name_hash.max_by do | k, v |
puts "k=#{k} v=#{v} 0 - v = #{0 - v}"
0 - v
end
puts "max=#{max.inspect}, class of value returned by max_by : #{max.class}"
result = name_hash.max_by {|k, v| 0-v}[0]
puts "result=#{result.inspect}"
result
end
key_for_min_value({a: 1, b: 2, c: 3})
key_for_min_value({})
Execution :
$ ruby -w t.rb
in key_for_min_value with parameter {:a=>1, :b=>2, :c=>3}
item=[:a, 1]
item=[:b, 2]
item=[:c, 3]
k=a v=1 0 - v = -1
k=b v=2 0 - v = -2
k=c v=3 0 - v = -3
max=[:a, 1], class of value returned by max_by : Array
result=:a
in key_for_min_value with parameter {}
max=nil, class of value returned by max_by : NilClass
t.rb:15:in `key_for_min_value': undefined method `[]' for nil:NilClass (NoMethodError)
from t.rb:21:in `<main>'
The documentation of enum.max_by says :
Returns the item corresponding to the largest value returned by the
block.
But if the enum is empty, it returns nil, from which you fetch element [0], which causes the error because there is no such method in the NilClass.
If you add return nil if name_hash.empty? at the beginning of the method, you prevent it to happen (with two uncommented lines) :
$ ruby -w t.rb
in key_for_min_value with parameter {:a=>1, :b=>2, :c=>3}
...
in key_for_min_value with parameter {}
about to return nil
There a lot of different possibilities to do what you want. The most obvious one is to literally translate the sentence: "return nil if the hash is empty" into Ruby:
def key_for_min_value(name_hash)
return nil if name_hash.empty?
name_hash.max_by {|k, v| 0-v}[0]
end
Another possibility would be to use the safe navigation operator:
def key_for_min_value(name_hash)
name_hash.max_by {|k, v| 0-v}&.[](0)
end
Yet another way would be to ensure that the value you are trying to index into is never nil:
def key_for_min_value(name_hash)
(name_hash.max_by {|k, v| 0-v} || [])[0]
end
# or
def key_for_min_value(name_hash)
Array(name_hash.max_by {|k, v| 0-v})[0]
end
I have just started a full-stack developer course at bloc.io, and I am struggling on an assignment. I cannot seem to find the issue with my code, but I am also a bit unclear as to what the assignment may be asking for. Any guidance would be greatly appreciated. The assignment gives the following examples. I apologize for the length of this post, but I wanted to be as thorough as possible.
def return_bigger(array)
array.map do |item|
yield(item)
end
end
return_bigger([1,2,3,4]) do |item|
item + 1000
end
#=> [1001, 1002, 1003, 1004]
return_bigger(["cat", "hat", "bat"]) do |item|
item.capitalize
end
#=> ["Cat", "Hat", "Bat"]
new_each([1,2,3,4]) do |item|
p "Whatever I want! Item: #{item}"
end
def new_each(array)
0.upto(array.length - 1) do |index|
yield( array[index] )
end
end
Then describes the assignment as follows:
Define a new_map function. It should take an array as an argument and return a new array modified according to the instructions passed in as a block. Feel free to use each within the method, rather than the array indexing we used above.
The first step in re-implementing map should be to iterate over the array:
def new_map(array)
array.each do |item|
end
end
The new_map method will be quite similar to our new_each method, but rather than just performing "side effect" behavior with each element, you'll want to store the return value from each block invocation in a new array:
def new_map(array)
new_array = []
array.each do |item|
# invoke the block, and add its return value to the new array
end
end
When you've finished iterating through the old array, just return the new one from your new_map function.
From what I can comprehend, the assignment wants me to replicate the new_each method without the use of .map then store it in a "new_array" However, I am unsure what the flaw in my code is. Is there a reason that my code is not "yielding" the blocks I have defined? This is the code I have come up with:
def new_map(array)
new_array = []
array.each do |item|
yield(item)
new_array << item
end
end
new_map([1,2,3,4]) do |item|
item + 1
end
new_map(["cat", "hat", "bat"]) do |item|
item.capitalize
end
assignment:
new_map should not call map or map!
RSpec::Expectations::ExpectationNotMetError
expected: [2, 3, 4]
got: [1, 2, 3]
(compared using ==)
exercise_spec.rb:9:in `block (2 levels) in <top (required)>'
new_map should map any object
RSpec::Expectations::ExpectationNotMetError
expected: [Fixnum, String, Symbol]
got: [1, "two", :three]
(compared using ==)
exercise_spec.rb:14:in `block (2 levels) in <top (required)>'
specs:
describe "new_map" do
it "should not call map or map!" do
a = [1, 2, 3]
a.stub(:map) { '' }
a.stub(:map!) { '' }
expect( new_map(a) { |i| i + 1 } ).to eq([2, 3, 4])
end
it "should map any object" do
a = [1, "two", :three]
expect( new_map(a) { |i| i.class } ).to eq([Fixnum, String, Symbol])
end
end
Two tiny mistakes: the fact that you are stuffing your new_array with original items, rather than with the transformed items that you are getting from yield item, and (as already mentioned by Cary Swoveland in comments) not returning new_array. As it is, you are returning the last computed value, which is the result of array.each, which is array - so instead of your computed result, you are returning the original array. This is why you are receiving [1, 2, 3] when you are expecting [1+1, 2+1, 3+1].
def new_map(array)
new_array = []
array.each do |item|
yield(item)
new_array << yield(item)
end
new_array
end
new_map([1,2,3,4]) do |item|
item + 1
end
new_map(["cat", "hat", "bat"]) do |item|
item.capitalize
end
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
I have some data saved in deeply nested Hashes and Arrays and I have run into trouble with the text encoding of the data. I know for fact that the texts are encoded in "UTF-8", so I decided to go over each element and force the encoding.
So, I created a method called deep_each for the Enumerable module:
module Enumerable
def deep_each(&block)
self.each do |element|
if element.is_a? Enumerable then
element.deep_each(&block)
else
block[element]
end
end
end
end
And expected to be able to fix the data using the following method call:
deephash.deep_each {|element| element.force_encoding("UTF-8") if element.class == String}
But the result was disappointing:
deephash.deep_each {|element| element.force_encoding("UTF-8") if element.class == String}
> RuntimeError: can't modify frozen String
> from (pry):16:in `force_encoding'
Then I moved the function down the hierarchy, to the "Array" and "Hash" classes:
class Hash
def deep_each(&block)
self.each do |element|
if [Array, Hash].include? element.class then
element.deep_each(&block)
else
block[element]
end
end
end
end
class Array
def deep_each(&block)
self.each do |element|
if [Array, Hash].include? element.class then
element.deep_each(&block)
else
block[element]
end
end
end
end
Surprisingly, the same call works now.
What constraint am I violating here, and how can I define a method for all Enumerables without defining it for every single one of them?
As far as I can tell, you should get the exact same error with both your Enumerable version and your Array/Hash monkey patch. I do. Are you sure you're using the same deephash in both cases?
Normally when you loop each on a hash, you'd pass in both key and value to the block. You're passing a single value element to the block. This then is an Array with the key and value:
irb> {a:1, b:2}.each {|el| puts el.inspect }
[:a, 1]
[:b, 2]
Your deep_each checks if this is an Enumerable, and it is, so it calls deep_each on the list. Then, finally, you reach the leafs and call the block on the key and the value. The block checks if it's working with a String, and if so, forces encoding.
If your hash key is a string, you will try to mutate it. But hash keys are frozen, and so RuntimeError: can't modify frozen String is raised.
irb> {a: {b: {c: "abc"}}}.deep_each { |el| el << "efg" if String === el}
=> {:a=>{:b=>{:c=>{:d=>"abcefg"}}}}
irb> {a: {b: {"c" => "abc"}}}.deep_each { |el| el << "efg" if String === el}
RuntimeError: can't modify frozen String
str = "\xE2\x82\xAC" #Euro sign in UTF-8
puts str.encoding #=> UTF-8
puts str #=> Euro sign in a UTF-8 enabled terminal window
File.open('data.txt', 'w:utf-8') do |f|
f.write("#{str}\n")
end
Encoding.default_external = 'ISO-8859-1'
str = File.read('data.txt')
puts str.encoding #=> ISO-8859-1
arr = [
{a: str},
{b: 'world'},
]
arr[0][:a].force_encoding('utf-8')
puts arr[0][:a].encoding #=> UTF-8
puts arr[0][:a] #=> Euro sign in a UTF-8 enabled terminal window
It would be more illustrative if you posted an example of: I have run into trouble with the text encoding of the data
Finally, it looks like writing the method for each class separately
makes more sense. For the Hash I need to use each_value rather than
each
You can do something like this:
iterator_for = Hash.new(:each) #When a non-existent key is looked up, return :each
iterator_for.update({
Hash => :each_value,
})
data = [
%w{ hello world goodbye },
{"a" => "red", "b" => "blue"},
]
data.each do |element|
element.send(iterator_for[element.class]) do |x|
puts x
end
puts '-' * 20
end
--output:--
hello
world
goodbye
--------------------
red
blue
--------------------
irb> pp config
[{"file"=>"/var/tmp"},
{"size"=>"1024"},
{"modified"=>"03/28/2012"}]
=> nil
In the code,
config.each do |d|
# then how to break d into (k, v)???
end
config.each do |items|
items.each do |key, value|
# e.g. key="file", value="/var/tmp", etc.
end
end
Just do
config.each do |hash|
(k,v),_ = *hash
end
Inspired by #Arup's answer, here's a solution that doesn't require a extra, unused variable in the parallel assignment:
config.each do |hash|
key, value = hash.to_a[0]
end
to_a converts the hash into the same kind of array that you would get by using splat *hash, but you can actually index the first element of the array (i.e. the first key/value pair) with [0] this way, while trying to do so with splat (*hash) generates a syntax error (at least in Ruby version 2.1.1):
>> k,v = (*hash)[0]
SyntaxError: (irb):4: syntax error, unexpected ')', expecting '='
k,v = (*x)[0]
^
from c:/RailsInstaller/Ruby1.9.3/bin/irb:12:in `<main>'
>>
Of course, depending on what you're going to do with the key and value variables, it might make your code shorter and more readable to use one of these standard block constructs:
config.each do |hash|
hash.each { |key,value| puts "#{key}: #{value}" }
end
# or
config.each do |hash|
hash.each do |key,value|
puts "#{key}: #{value}"
end
end