From: Phrogz Date: 2007-03-20T06:55:10+09:00 Subject: Re: Sorting Dates and Times in an array On Mar 19, 3:02 pm, "Paul" wrote: > On Mar 19, 4:43 pm, "Phrogz" wrote: > > a) Ruby doesn't have multi-dimensional arrays in the core. Unless > > you're using something like NArray, I suspect you're thinking of > > arrays of arrays. > > Maybe I am thinking of that.. I don't know that terminology. I > understand a multi-dimensional array, but haven't heard of an "array > of arrays" before. They sound the same to me. I'll go with your > phrase. =) Consider: a1 = [ [ 1, 2, 3 ], [ 4, 5, 6 ], [ 7, 8, 9 ] ] This looks like a 3x3 array, since you can ask for the value at row 2, column 0 with a1[2][0]. However, it's really four arrays - one array with three elements, each of which is an array of 3 elements. But the 'dimensionality' isn't guaranteed: a2 = [ [ 1, 2, 3, 4 ], nil, [ 5 ], [ 6, 7, 8, 9, 10 11 12 ] ] You can still ask for a2[2][0], but if you ask for a2[1][0] you'll get a runtime error when you try to call the #[] method on that nil value. A true 2-dimensional array would be a single object with the ability to always access any one of the n x m entries, usually with notation like a3[ 2, 0 ]. > Okay, so I don't know what the difference is between these two: > > > @data.sort! { |a,b| b[x].to_f <=> a[x].to_f } # i.e. descending numeric sort > and > > @data.replace( @data.sort { |a,b| b[x].to_f <=> a[x].to_f } ) # i.e. descending numeric sort The former sorts the original array in-place. The latter first creates a new copy of the original array that is sorted (the return value of #sort) and then replaces the original with that array. An extra array is created en route. > When I checked the Programming Ruby reference it says that Array#map! > is a 'synonym for Array#collect!' and when I check Array#collect! I > don't think it's what I want in this sort function. Or if it is, I > don't know how to write the code for it. And until today I had never > seen 'sort_by' so I'm still trying to figure out that function too. map! is useful if you're trying to transform the values in one array into another set of values. For example: irb(main):001:0> a = [ "1", "12", "3.1415" ] => ["1", "12", "3.1415"] irb(main):002:0> b = a.map{ |x| x.to_i } => [1, 12, 3] irb(main):003:0> a => ["1", "12", "3.1415"] As you can see, a new array was created (that 'b' now refers to), but the original values in 'a' are preserved. However: irb(main):004:0> a.map!{ |x| x.to_i } => [1, 12, 3] irb(main):005:0> a => [1, 12, 3] The exclamation point indicates (in this case) that the array is being modified in place. So, if you find that 'normal' methods are using up too much memory, and you don't need the original values, my suggestion was: a.map!{ ...convert strings to Time objects, losing the strings... } a.sort!{ ...sort as you see fit... } a.map!{ ...if you need to, convert them to something else... } Read the documentation on the sort_by method to see how it works. It's relevant to this discussion that it creates an additional array as it goes (to store the sort keys and values in, and then the values themselves). There is no sort_by! method to do it in-place. However, all this discussion smells like premature optimization. If you have an array of 100 items that each 'weigh' 1MB, and then you create 3 copies of that array, you have NOT allocated an extra 300MB. Each copy of the array has the same lightweight references to those same heavy objects. Before you spend too much time wondering about the internal implementation and mangling your code in order to make it as optimal as possible, you should be certain that the 'problem' you're working around is really a problem.