for i in 0...array.size
p array[i]
end
Hey, I know that this is an inefficient way to act upon every element in an array, and I know that this is better:
array.each {|i| print i}
What I was wondering was two things:
(1)
Is this:
for i in array
print i
end
equivalent to the .each way? Or is it done in a different way? And
(2) Is there a way in the .each method to retrieve the current element's index?
i.e. If you don't want to print out i but instead print out index, i. For purposes of demonstrating what I mean, this would be done like the following by the first method of acting on every element of the array
for i in 0...array.size
p i, array[i]
end
(1)
My guess is that it is faster than the for i in 0...array.size while slower than the .each method.
My reasoning:
for i in 0...array.size
p array[i]
end
# Is pretty much equivalent to
(0...array.size).each {|i| p array[i]}
There are probably some variable scope issues if you tried that code, but you should get the idea.
You iterator over another object to get an object which is then used to retrieve an object from the array.
Accordingly to Blizzard the .each is faster than using a for loop. How fast and if the different is significant I do not know. Though considering the different scope I can easily imagine that using .each is faster.
(2)
There is no direct way to retrieve the index. You can use array.index(i) to retrieve the index, but not only is that slow, it only returns the index of the first matching value. Searching for elements in an array is so slow that in almost all cases using the for i in 0...array.size way is faster. In addition it is easier to manage and keep track of.
Only use the iterator way (for element in array) if the index is irrelevant.
If the index is relevant then you could this:
array.each_with_index {|element, index| p index, element}
If you want to know the .each method is implemented as the Visitor Pattern (http://en.wikipedia.org/wiki/Visitor_pattern)
It can be used on any Enumerable (http://www.ruby-doc.org/docs/ProgrammingRuby/html/ref_m_enumerable.html) collection.
There exist collections where the order the elements are retrieved can be stochastic and some where the concept of indexes doesn't make sense.
The index with the .each_with_index method shows how many elements was retrieved before it.
*hugs*
- Zeriab
Cool. Thanks; that answered my question perfectly. You're awesome, Zeriab :D
I didn't know about .each_with_index either. Thanks again.
How you conduct a test on the speed of the different constructions?
I want to know how fast each construction runs. I want you test this.
I am sure it will be a useful experience ^^
So, how do you plan to do it?
In addition to put forward the average speed difference you should explain how the tests was conduct in a convincing way.
Sort of the proof that you have done your work properly.
Good luck
*hugs*
- Zeriab
*cries
I suppose I would try this:
Take an arbitrarily large array, and apply each construction successively (each doing the same thing; not print statements for sure :P). Upon completion of each construction's algorithm, record the time taken for the algorithm to complete.
Maybe I should try this for various types of algorithms - some simple, some heavy, some requiring index. I should also probably keep track of CPU Usage.
Try it. Tell me how it went.
If you learned anything, tell me that as well
Failure :P
I tried this code:
class Test_Object
attr_reader :id
attr_reader :test_variable
def initialize (id)
@id = id
@test_variable = 0
end
def test
# This is just a random method call
@test_variable += 1
end
end
class Test
def initialize
test_array = []
for i in 0...1200000
test_array.push (Test_Object.new (i))
end
p 'Test A Begins'
for i in 0...test_array.size
test_array[i].test
end
p 'Test A Completed'
p 'Test B begins'
for i in test_array
i.test
end
p 'Test B completed'
p 'Test C begins'
test_array.each {|i| i.test}
p 'Test C completed'
end
end
Under the basic idea that the best test would be to do the same thing to each of the items in the array. However, for large large numbers, the script would hang on the first part. For smaller numbers (like 1200000), the tests would complete so quickly as to make it nearly impossible to time to any degree of precision. That being said, the first two performed in roughly the same time (slightly less than 2 seconds) and the 3rd was faster (about a second or less)
I will try to find a better way to test the script that hopefully will not hang at the first part.
I suggest you do a Graphics.update between each test.
The script-hanging error comes when Graphics.update isn't called after a certain amount of time.
You can just use the system time to figure out the differences in time from before and after the test. (http://www.ruby-doc.org/docs/ProgrammingRuby/html/ref_c_time.html)
Store the results of each run.
Run the test a decent amount of times. Let's just say 30 or 50. Whatever you find suitable.
Give a schema of the test results and draw conclusions out from the schema.
Good luck ^_^
Edit: Btw. would this test code be reliable? (Note: I didn't include time because you have to figure that part out yourself ;))
I use algorithms with a complexity of n2 instead of n.
class Test_Object
attr_reader :id
attr_reader :test_variable
def initialize (id)
@id = id
@test_variable = 0
end
def test
# This is just a random method call
@test_variable += 1
end
end
class Test
def initialize
test_array = Array.new(2000)
for i in 0...test_array.size
test_array[i] = Test_Object.new(i)
end
p 'Test A Begins'
for i in 0...test_array.size
for j in 0...test_array.size
test_array[i].test
end
end
p 'Test A Completed'
p 'Test B begins'
for i in test_array
for j in test_array
i.test
end
end
p 'Test B completed'
p 'Test C begins'
test_array.each {|i| test_array.each{|j| i.test}}
p 'Test C completed'
end
end
Test.new