ruby rename elements of array with elements of different array - ruby

i have a file that looks like this:
TTITLE0=track name 1
TTITLE1=track name 2
and a directory that contains track01.cdda.wav.mp3 and track02.cdda.wav.mp3
i have the following code, which creates 2 different arrays, 1 with the track names and 1 with the track titles:
tracks = Dir.glob("*.mp3")
tracknames = Array.new
File.open('read').each do |line|
if line =~ /TTITLE/
tracknames << line.split("=")[1].strip!
end
end
this gives me 2 arrays:
["track name 1", "track name 2"]
and
["track01.cdda.wav.mp3", "track02.cdda.wav.mp3"]
i would like to rename the files in the second array with the elements of the first array. so, "track01.cdda.wav.mp3" would become "track name 1.mp3".
here is what i have tried so far:
tracks.map {|track| File.rename("#{tracks}", "#{tracknames}.mp3") }
and i get the error:
No such file or directory - track01.cdda.wav.mp3track02.cdda.wav.mp3 or track name 1track name 2 (Errno::ENOENT)
i have to keep in mind that in the future there could be any number of elements in each array, but the numbers will be equal to each other.
any ideas?

Use Array#zip:
tracks.zip(tracknames).each do |track, trackname|
File.rename track, "#{trackname}.mp3"
end
Alternatively (less fun, but doesn't create an intermediary array of arrays prior to enumeration):
tracks.each_with_index do |track, i|
File.rename track, "#{tracknames[i]}.mp3"
end

Do you really need to have two arrays? You could get by with just one:
tracks = Dir.glob("*.mp3")
File.open('read').each do |line|
if line =~ /TTITLE/
to = line.split("=")[1].strip!
File.rename tracks.shift, "#{to}.mp3"
end
end
And then end of that, your shift calls will have left tracks empty but that may not be a problem.
As far as your:
tracks.map {|track| File.rename("#{tracks}", "#{tracknames}.mp3") }
approach goes, the problem is that you're calling to_s on the tracks array when you interpolate it as "#{tracks}" and that just mashes all the individual strings in tracks together as one big pile of "not what you want". Similarly for tracknames. And map isn't what you want as you're not doing anything with the File.rename return values. However, you could do this:
tracks.each {|track| File.rename("#{track}", "#{tracknames.shift}.mp3") }
Or use each_with_index:
tracks.each_with_index {|track,i| File.rename("#{track}", "#{tracknames[i]}.mp3") }
That one would leave tracknames intact.

Related

Last element of the ruby array is nil

I have a simple ruby program that has 2 steps so far
1. Ask the user for the number of stock market symbols they want to track
2. Ask the user to input these symbols
puts("How many stocks do you want to track ?")
numStocks = gets.chomp()
puts("Please enter #{numStocks} stock symbols: ")
array = Array.new(numStocks.to_i)
for i in 1..numStocks.to_i do
array.insert(i-1, gets.chomp())
end
puts("Stock symbols entered ... #{array}")
The output that is printed onto the console is
Stock symbols entered ... ["aapl", nil]
Why is the last element of the array nil in this case and what's the proper way to get rid of it ?
Array.new creates a new array, filling it with the quantity of elements you specified. Array.new(3) is the same as [nil, nil, nil]. Array.new(2, 'a') is the same as ['a', 'a'].
You then use array.insert which adds instead of replaces the elements. You could use array[i-1] = gets.chomp() to set the values, but there's really no reason to initialize the array this way at all.
A "more Ruby" way to write this all would be:
puts 'How many stocks do you want to track ?'
num_stocks = gets.chomp
puts "Please enter #{num_stocks} stock symbols: "
array = 1.upto(num_stocks.to_i).map do
gets.chomp
end
puts "Stock symbols entered ... #{array}"
EDIT:
Also, it’s worth mentioning that in Ruby, arrays are not a fixed size. You can add and remove elements from them as you please. If I had to guess, you’re used to languages like C, where you have to define the size of your array up front and then it’s just that size forever (that’s what I’m guessing you were trying to do anyways).
And another thing, in Ruby it’s not very common to use Array.new. Most times people just define an array by typing an array literal.
array = [1,2,3]
A ruby array is more like a List in other languages. It supports push (though << is a more common method for adding to an array), pop, and other list-like features.
Thats because when you do Array.new(numStocks.to_i) it initializes an array with 3 nil values and you keep adding on to it,
the proper way to get rid of nil from array is to use .compact on the array but I suggest you change your logic,
maybe something like this
puts("How many stocks do you want to track ?")
numStocks = gets.chomp()
puts("Please enter #{numStocks} stock symbols: ")
array = Array.new() # or array = []
numStocks.to_i.times do
array << gets.chomp()
end
puts("Stock symbols entered ... #{array}")
or you could ask the user to enter the comma separated symbols, so you don't have to loop, and split them,
puts("Please enter #{numStocks} stock symbols separated by commas (a,b): ")
symbols = gets.chomp().split(',')
puts("Stock symbols entered ... #{array}")

SQLite3 with Ruby, Cannot Search Resulting Array (iterates over array as if it were one giant element)

I've been trying to find an answer for a little while now, and I'm not sure if I'm asking the wrong questions, but I've had no luck so far.
I have an array generated from querying an SQLite table. I also have an array of times generated from a csv file. I am trying to pull the time[0] (an id number) and check if it exists in the array from the SQL table
array = []
SQLite3::Database.new("t.db") do |db|
db.execute ("SELECT t FROM ts") do |row|
array << row
end
end
times = CSV.read('times1.csv')
times.each do |time|
#puts "This is the trip id: #{time[0]}"
if array.include? time[0]
puts time[0]
end
end
When I do this, I get no results. I know for a fact that there should be a few matches. When I try to iterate over the array like:
array.each do |row|
if row = 2345
puts "Match found"
end
end
Here is the strange part that has really stumped me. I know that 2345 only comes up once or twice in the array, however when I run this code, it seems as though it prints "Match found" for every element (like 5,000 times it says "Match found"). I feel like something is wrong with the array generated from the SQLite but I can't for the life of me figure it out.
Any ideas? Thanks.
In here:
db.execute ("SELECT t FROM ts") do |row|
your row is an array whose sole element is the t you're after. That means that you end up with an array-of-arrays in array rather than an array of numbers and of course your array.include? time[0] check fails because array only contains other arrays.
You probably want to say:
array << row[0]
to collect the t values in array.

Ruby Array#transpose real world example

Does anyone have a real-world example of a situation where Array#transpose would be useful? I'm struggling to relate the functionality to possible applications.
Consider the following example:
class Array
def mean
reduce(:+) / length
end
end
locations = [
[41.311000, -96.138319],
[41.311355, -96.130380],
[41.315319, -96.138319],
[41.316093, -96.129994],
[41.317640, -96.124372],
[41.315964, -96.121883],
[41.313128, -96.121968],
[41.313160, -96.125101],
[41.309775, -96.125316]
]
latitudes, longitudes = locations.transpose
puts latitudes.inspect
# => [41.311, 41.311355, 41.315319, 41.316093, ...
puts longitudes.inspect
# => [-96.138319, -96.13038, -96.138319, -96.129994 ...
weighted_center = [latitudes.mean, longitudes.mean]
puts weighted_center.inspect
# => [41.31371488888889, -96.12840577777779]
transpose can be thought of as the opposite of zip
It might be useful if you had a collection of names. The first element might be a first name and the second element might be a last name.
You might want to get a list of the first names or the last names
names = [["John", "Smith"],["Roger", "Jones"]]
You could get the first names by calling names.transpose.first

Why is the method deleting the element inside my array?

I'm trying to create my own .sort method as an exercise in a ruby book, using recursion, and for some reason they haven't taught me the spaceship operator yet. My code works to get the smallest value - apple - and puts it in the sorted array, and it even repeats using the recursion, and resets the array to repeat the process to add the second smallest word. The problem is for some reason it removes the smallest word -apple- and I can't figure out why. I know where I think - in the else myArray.length == 1 statement when I pop the element off the array, but why is it removing from the sortedArray too?
sortedArray ends up with value apple, then when it does recursion it SHOULD be sortedArray = ['apple', 'banana' …] but it removes apple, then it removes banana etc… until I end up with sortedArray = ['quincy']
I have tried moving my arrays to multiple places, and I've tried adding to the sortedWords array in multiple places but it is always deleting or resetting the sortedWords array.
It looks like I'm really close since I've got the alphabetizing working. How do I get it to add all the items to the sortedWords array?
ArrayofWords = ['cat', 'dog', 'bat', 'elephant', 'apple', 'banana', 'quincy', 'boo']
# Why is it deleting, or replacing my sortedWords array? If you run this code you will notice that the sortedWords array
# is giving me the smallest word in the array, but then I add the recursive part, and somehow the previous smallestword
#gets deleted... but I have never in any part of my code say delete or replace the sorted array...
def sortTheArray myArray
unsortedWords = []
sortedWords = []
smallestValue = ''
while myArray.length != 0
if myArray.first < myArray.last
unsortedWords.push(myArray.last)
myArray.pop
elsif myArray.first > myArray.last
unsortedWords.push(myArray.first)
myArray.delete_at(0)
else myArray.length == 1
sortedWords.push(myArray.first)
myArray.pop # This is my problem area I think???
end # if else
#puts 'sorted words'
#puts sortedWords
#puts 'unsortedWords'
#puts unsortedWords
end # while
puts 'sorted words'
puts sortedWords
puts 'unsortedWords'
puts unsortedWords
myArray = unsortedWords
while myArray.length > 0
sortTheArray myArray
end #while
end # sortTheArray
sortTheArray ArrayofWords
most of those puts's are not necessary, I was just trying to figure out where the problem was.
You've got numerous problems with your code. For example, you seem to want to accumulate sorted words across invocations of this method, but you reinitialize sorted_words to [] at the start of the method block.
I would suggest first trying to express your recursive solution in English as simply as possible and then seek to implement it.
For example, the following is an approach which seems to be in line with what you are trying to do:
def sorted_array(array)
lowest_value prepended to the sorted_value of the array with the lowest_value removed
end
I'm sharing the above because it appears that you're new to Ruby and just implementing the above in an idiomatic fashion will be a good challenge.

Can't convert String onto integer (TypeError)

Following code return error "Can't convert String onto integer", please help
subject = ['eng','Math','Sci']
grade = ['grade 1','grade 2','grade 3']
subject.each do |sub|
puts ("some string")
grade[sub] .each do |grd|
puts ("some string")
end
end
grade[sub] .each do |grd| thats the problem.
Array elements are accessed by using a index of integer or a range of integers.
You are trying to access a array element by using the variable stored in sub. Since this is a ordinary .each loop it will loop all the elements in the array, in this case 'eng','Math','Sci'. If you want the position of for example 'eng' you could use a .each_with_index
it should probably just be
grade.each do |grd|
with each_with_index it would be
subject.each_with_index do |sub, index|
print sub
print grade[index]
end
If you want a subject -> grade collection it might be good to look into using a Hash like Dave Newton said.
{"eng" => "grade 1","Math" => "grade 2","Sci" => "grade 3"}.each do |subject, grade|
puts "#{subject| #{grade}"
end
When you do
grade[sub] .each do |grd|
Ruby expects sub to be using an integer to reference a position in the list of grades.
subject and grade are both arrays. They can only be accessed by their position. In your each loop, the block gets the actual element (in sub), not the position. So in line 5, you are trying to access grade['eng'], which will not work and produces the error. Note that unlike in e.g. PHP, an array and a hash (an associative array) are different things.
Guessing from your code, you might want to use each_index instead of each which will pass the index number to the block instead of the element.
I'm not sure I understand what you're trying to achieve; however, if you'd like to print subjects and grades and you're sure about the relative order of elements in the arrays, you could do this:
subject = ['eng','Math','Sci']
grade = ['grade 1','grade 2','grade 3']
subject.each_with_index do |sub, idx|
puts "#{sub} - #{grade[idx]}"
end
Output:
eng - grade 1
math - grade 2
sci - grade 3
An hash is however probably more suitable to your needs.

Resources