Is the .each iterator in ruby guaranteed to give the same order on the same elements every time?
This depends on the specific Enumerable
object you are operating on.
Arrays for example will always return elements in the same order. But other enumerable objects are not guaranteed to behave this way. A good example of this is the 1.8,7 base Hash. That is why many frameworks (most notably ActiveSupport) implement an OrderedHash.
One interesting side note: Even Hash
will return objects in the same order if the hash has not changed between each
calls. While many objects behave this way, relying on this subtlety is probably not a great idea.
So, no. The generic each
will not always return objects in the same order.
P.S. Ruby 1.9's hashes are now actually ordered http://www.igvita.com/2009/02/04/ruby-19-internals-ordered-hash
Hash ordering preserved between iterations if not modified?
Prior to 1.9, behavior of enumerated hashes was not in the ruby specification and therefore was up to implementation -- basically, hash enumeration behavior/pattern was undefined by the language and implementations could really do whatever they want (random? sorted? insertion order? different method every time? anything goes!)
1.9+, hash enumeration is specified by the language to be in the order of insertion, so if you know your platform is 1.9+, you can rely on it.
RubySpec
Is order of a Ruby hash literal guaranteed?
There are couple of locations where this could be specified, i.e. a couple of things that are considered "The Ruby Language Specification":
- the ISO Ruby Language Specification
- the RubySpec project
- the YARV testsuite
- The Ruby Programming Language book by matz and David Flanagan
The ISO spec doesn't say anything about Hash
ordering: it was written in such a way that all existing Ruby implementations are automatically compliant with it, without having to change, i.e. it was written to be descriptive of current Ruby implementations, not prescriptive. At the time the spec was written, those implementations included MRI, YARV, Rubinius, JRuby, IronRuby, MagLev, MacRuby, XRuby, Ruby.NET, Cardinal, tinyrb, RubyGoLightly, SmallRuby, BlueRuby, and others. Of particular interest are MRI (which only implements 1.8) and YARV (which only implements 1.9 (at the time)), which means that the spec can only specify behavior which is common to 1.8 and 1.9, which Hash
ordering is not.
The RubySpec project was abandoned by its developers out of frustration that the ruby-core developers and YARV developers never recognized it. It does, however, (implicitly) specify that Hash
literals are ordered left-to-right:
new_hash(1 => 2, 4 => 8, 2 => 4).keys.should == [1, 4, 2]
That's the spec for Hash#keys
, however, the other specs test that Hash#values
has the same order as Hash#keys
, Hash#each_value
and Hash#each_key
has the same order as those, and Hash#each_pair
and Hash#each
have the same order as well.
I couldn't find anything in the YARV testsuite that specifies that ordering is preserved. In fact, I couldn't find anything at all about ordering in that testsuite, quite the opposite: the tests go to great length to avoid depending on ordering!
The Flanagan/matz book kinda-sorta implicitly specifies Hash
literal ordering in section 9.5.3.6 Hash
iterators. First, it uses much the same formulation as the docs:
In Ruby 1.9, however, hash elements are iterated in their insertion order, […]
But then it goes on:
[…], and that is the order shown in the following examples:
And in those examples, it actually uses a literal:
h = { :a=>1, :b=>2, :c=>3 }
# The each() iterator iterates [key,value] pairs
h.each {|pair| print pair } # Prints "[:a, 1][:b, 2][:c, 3]"
# It also works with two block arguments
h.each do |key, value|
print "#{key}:#{value} " # Prints "a:1 b:2 c:3"
end
# Iterate over keys or values or both
h.each_key {|k| print k } # Prints "abc"
h.each_value {|v| print v } # Prints "123"
h.each_pair {|k,v| print k,v } # Prints "a1b2c3". Like each
In his comment, @mu is too short mentioned that
h = { a: 1, b: 2 }
is the same ash = { }; h[:a] = 1; h[:b] = 2
and in another comment that
nothing else would make any sense
Unfortunately, that is not true:
module HashASETWithLogging
def []=(key, value)
puts "[]= was called with [#{key.inspect}] = #{value.inspect}"
super
end
end
class Hash
prepend HashASETWithLogging
end
h = { a: 1, b: 2 }
# prints nothing
h = { }; h[:a] = 1; h[:b] = 2
# []= was called with [:a] = 1
# []= was called with [:b] = 2
So, depending on how you interpret that line from the book and depending on how "specification-ish" you judge that book, yes, ordering of literals is guaranteed.
Check if two arrays have the same contents (in any order)
This doesn't require conversion to set:
a.sort == b.sort
Does an STL map always give the same ordering when iterating from begin() to end()?
Yes, it maintains an internal order, so iteration over a set that isn't changing should always be the same. From here:
Internally, the elements in the map
are sorted from lower to higher key
value following a specific strict weak
ordering criterion set on
construction.
Ruby's all? method has an order or it's random?
Yes, it evaluates the condition block in the order of the elements in the array. When there is an element that returns a falsy value against the block, iteration stops at that element, and the block will not be evaluated against further elements. So when the code in the block has side effect, the order of the elements in the array does have consequence.
Why Ruby's array of 1000 hashes' key and value pairs are always in a particular order?
The layout of the hash is deterministic. So for a particular version of ruby, if you always add/remove the keys of a hash in the same order, the layout of the hash will be the same. This means iterating over the hashes in your array will have the keys all in the same order.
what's different between each and collect method in Ruby
Array#each
takes an array and applies the given block over all items. It doesn't affect the array or creates a new object. It is just a way of looping over items. Also it returns self.
arr=[1,2,3,4]
arr.each {|x| puts x*2}
Prints 2,4,6,8 and returns [1,2,3,4] no matter what
Array#collect
is same as Array#map
and it applies the given block of code on all the items and returns the new array. simply put 'Projects each element of a sequence into a new form'
arr.collect {|x| x*2}
Returns [2,4,6,8]
And In your code
a = ["L","Z","J"].collect{|x| puts x.succ} #=> M AA K
a is an Array but it is actually an array of Nil's [nil,nil,nil] because puts x.succ
returns nil
(even though it prints M AA K).
And
b = ["L","Z","J"].each{|x| puts x.succ} #=> M AA K
also is an Array. But its value is ["L","Z","J"], because it returns self.
Related Topics
Ruby: Converting from Float to Integer in Ruby Produces Strange Results
Ruby-Rails Serve Ftp File Direct to Client
Removing or Overriding an Activerecord Validation Added by a Superclass or Mixin
Generate All "Unique" Subsets of a Set (Not a Powerset)
Rails Error Method_Missing': Undefined Method 'This' for Gem::Specification
Access Current Git Commit Number from Within Heroku App
Rails 3 Cli Executes Commands Really Slow
Wrapping Text into Lines at Word Boundaries
Keyword Arguments Unpacking (Splat) in Ruby
Encoding::Undefinedconversionerror: "\Xe4" from Ascii-8Bit to Utf-8
Working with Decimals in Ruby on Rails 3
Rbenv Install Ruby Build Failed