41

I'm running Ruby 1.9.3p392.

Item = Struct.new( :name, :dir, :sort_dir )

entries = ftp.list()
entries.map!{|e| Net::FTP::List.parse(e) }.map!{|e| Item.new( e.basename, e.dir?, (e.dir? ? 0 : 1) ) }

render json: entries.sort_by{ |e| [ e.sort_dir, e.name ]}

For some reason, I am not getting the results back as expected.

I do get all folders first followed by all files, however, the name sorting is failing.

As an example, I get these for my folders:

  1. content
  2. images
  3. bin

For files:

  1. global.asax
  2. web.config
  3. favicon.ico

It groups the dir/file portion correct, but the names are sorted incorrectly.

The output to the console looks like this after sorting:

#<struct FtpController::Item name="Content", dir=true, sort_dir=0>
#<struct FtpController::Item name="Images", dir=true, sort_dir=0>
#<struct FtpController::Item name="Scripts", dir=true, sort_dir=0>
#<struct FtpController::Item name="Views", dir=true, sort_dir=0>
#<struct FtpController::Item name="bin", dir=true, sort_dir=0>
#<struct FtpController::Item name="Global.asax", dir=false, sort_dir=1>
#<struct FtpController::Item name="Web.config", dir=false, sort_dir=1>
#<struct FtpController::Item name="favicon.ico", dir=false, sort_dir=1>
#<struct FtpController::Item name="packages.config", dir=false, sort_dir=1>
#<struct FtpController::Item name="robots.txt", dir=false, sort_dir=1>
0

1 Answer 1

79

Your sorting works correctly in MRI Ruby 1.8.7, 1.9.3, and 2.0.0:

Item = Struct.new(:name, :dir, :sort_dir)

entries = [Item.new('favicon.ico', false, 1), Item.new('bin', true, 0),
           Item.new('web.config', false, 1), Item.new('images', true, 0),
           Item.new('global.asax', false, 1), Item.new('content', true, 0)]

entries.sort_by{|e| [e.sort_dir, e.name]}
# => [#<struct Item name="bin", dir=true, sort_dir=0>,
#     #<struct Item name="content", dir=true, sort_dir=0>,
#     #<struct Item name="images", dir=true, sort_dir=0>,
#     #<struct Item name="favicon.ico", dir=false, sort_dir=1>,
#     #<struct Item name="global.asax", dir=false, sort_dir=1>,
#     #<struct Item name="web.config", dir=false, sort_dir=1>]

Have you tried outputting the result of your sort_by to a console? I'm not familiar with the render json: portion of your code, but perhaps that's where things are going wrong. My best guess is that somehow in the conversion to JSON (if that's what it does) the sorting is getting messed up.

My other idea is that perhaps you expect sort_by to modify entries; it does not. If you want entries itself to be sorted after the call, use sort_by! (note the ! at the end of the method name).

Update: It looks like the issue is that you want a case-insensitive search. Simply adding upcase should do the trick:

entries.sort_by{|e| [e.sort_dir, e.name.upcase]}
Sign up to request clarification or add additional context in comments.

4 Comments

I included the console output into original question. Also, I am not expecting entries itself to be sorted. I'm expecting it to return a sorted list back to the render method. However, the json that I get back and the console output matches.
@Mike It looks like the issue is that you want a case in-sensitive sort, then? Because your output is sorted, just upper-case first.
can you add your comment as an answer so I can vote it as being correct. I added a downcase to name and it's working as expected. Thanks!
how would this for three conditions instead of two, and different order for different conditions is required in sorting? Eg. I have database enteries with columns date, timestamp, status. I was trying to sort the results by date (descending order), then status (ascending) and then time (ascending order) Date is not a actual column, i'm retrieving date using timestamp.to_date Trying this 'code'@results = @results.sort_by { |x| [-x.timestamp.to_date, x.status, x.timestamp]} to get desired order is failing, because x.timestamp.to_date is not integer.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.