From: Rob Biedenharn Date: 2009-03-20T06:18:08+09:00 Subject: Re: Complex sort of matrix possible, e.g. like Excel? On Mar 19, 2009, at 4:42 PM, RichardOnRails wrote: > On Mar 18, 12:31 pm, Rob Biedenharn > wrote: >> On Mar 18, 2009, at 1:58 AM, Christopher Dicely wrote: >> >>> Enumerable#sort lets you do this fairly easily with just a pure >>> array >>> of arrays, e.g., to sort the array-of-arrays "arr" by the first >>> column >>> ascending and the second descending: >> >>> arr.sort {|a,b| [a[0]<=>b[0], b[1]<=>a[1]].find {|x| x!=0} || 0} >> >> Not to detract to much from the other responses, but this ought to >> be: >> >> arr.sort {|a,b| (a[0] <=> b[0]).nonzero? || b[1] <=> a[1] } >> >> Take a look at what Numeric#nonzero? does. The docs specifically >> mention its use when chaining comparisons this way. >> >> Doing arr.sort_by {|a| [a[0], -a[1]] } only works if the second >> element responds to @- (like any Numeric would, but certainly not >> String). >> >> -Rob >> >>> On 3/17/09, RichardOnRails >>> >>> wrote: >>>> Hi, >> >>>> I've got an array of rows (and thus a matrix) created user >>>> FasterCSV >>>> to extract data from a CSV file. I'd like to sort the matrix on >>>> column A ascending and, within that, column B descending. I looked >>>> at >>>> Matrix, but it doesn't seem to address that functionality. Is >>>> there >>>> a package that does, or do I have to write my own SuperMatrix >>>> inherited from Matrix? >> >>>> Thanks in Advance, >>>> Richard >> >> Rob Biedenharn http://agileconsultingllc.com >> R...@AgileConsultingLLC.com > > On Mar 18, 12:31 pm, Rob Biedenharn > wrote: >> On Mar 18, 2009, at 1:58 AM, Christopher Dicely wrote: >> >>> Enumerable#sort lets you do this fairly easily with just a pure >>> array >>> of arrays, e.g., to sort the array-of-arrays "arr" by the first >>> column >>> ascending and the second descending: >> >>> arr.sort {|a,b| [a[0]<=>b[0], b[1]<=>a[1]].find {|x| x!=0} || 0} >> >> Not to detract to much from the other responses, but this ought to >> be: >> >> arr.sort {|a,b| (a[0] <=> b[0]).nonzero? || b[1] <=> a[1] } >> >> Take a look at what Numeric#nonzero? does. The docs specifically >> mention its use when chaining comparisons this way. >> >> Doing arr.sort_by {|a| [a[0], -a[1]] } only works if the second >> element responds to @- (like any Numeric would, but certainly not >> String). >> >> -Rob >> >>> On 3/17/09, RichardOnRails >>> >>> wrote: >>>> Hi, >> >>>> I've got an array of rows (and thus a matrix) created user >>>> FasterCSV >>>> to extract data from a CSV file. I'd like to sort the matrix on >>>> column A ascending and, within that, column B descending. I looked >>>> at >>>> Matrix, but it doesn't seem to address that functionality. Is >>>> there >>>> a package that does, or do I have to write my own SuperMatrix >>>> inherited from Matrix? >> >>>> Thanks in Advance, >>>> Richard >> >> Rob Biedenharn http://agileconsultingllc.com >> R...@AgileConsultingLLC.com > > Hi Rob, > > Thanks for your response. I don't want to be an expert on sorting > matrices. I just want to get my project working. (Don't we all :-) > > Here's the essence of what I've got working, confirmed with debugging > puts'. > > matrix = [] > FasterCSV.foreach(selectedCsvFile, :headers => false) do |row| > matrix << row > end > > I want (in Excel terms) the matrix sorted on column B asc. and within > that col. I asc. Both columns are textual. Based on your guidance, I > added the line: > > sortedMatrix = matrix.sort {|a,b| [a[1]<=>b[1], a[8] <=> b[8]]} > > Ruby gave me a syntax error: > ProcessExports.rb:130:in `sort': undefined method `>' for [-1, > 1]:Array (NoMethodError) > > I'm hoping the problem is that I'm invoking Array::Sort rather than > Enumerable::Sort but nothing my deteriorating brain could devise > worked. Any ideas. > > Best wishes, > Richard Well, my guidance was: arr.sort {|a,b| (a[0] <=> b[0]).nonzero? || b[1] <=> a[1] } Which translates to your: sortedMatrix = matrix.sort {|a,b| (a[1]<=>b[1]).nonzero? || a[8] <=> b[8] } You might also need: matrix << row.to_a or matrix << row.fields in your loop, but a FasterCSV::Row probably behaves sufficiently like an Array to sort properly. Whether it continues to behave later (when you *really* need an Array), may resolve the question of whether you need to call #to_a or #fields on your row. Real code will always get you a better answer that pseudo-code. If you meant for either sort on Col.B or Col.I to be *descending*, then swap the a and b in the appropriate expression. (Your original question had the secondary sort descending, but the latest [with code ;-)] says "col. I asc.") -Rob Rob Biedenharn http://agileconsultingllc.com Rob@AgileConsultingLLC.com