【问题标题】:Sort a ruby hashmap对 ruby​​ 哈希图进行排序
【发布时间】:2014-03-03 19:11:13
【问题描述】:

我有以下代码行

<% map = options_for_select(User.all.map {|u| [u.first_name+" "+u.last_name, u.id]}) %>

获取用户的名字和姓氏并在表单中提交其 ID。现在我添加了一些用户,他们不是按字母顺序排列的。如何按名字对这张地图进行排序?

【问题讨论】:

    标签: ruby-on-rails ruby ruby-on-rails-4 hashmap


    【解决方案1】:

    您也可以使用order 来获取已从数据库中排序的行:

    <% map = options_for_select(User.all.order(:first_name).map {|u| [u.first_name+" "+u.last_name, u.id]}) %>
    

    【讨论】:

    • 这里可能是更好的方法,可能更有效,特别是如果数据库对用于排序的属性有索引。
    • @DaniëlKnippers 是的,非常正确。有更好的方法(对于任何事情)。但它们只有在被证明时才会更好。你将如何证明这一点?我很想看到证据,因为我愿意采用它。
    • @Bala 如果数据库在name 属性上有一个索引,它已经知道顺序(据我所知,索引总是排序的,否则它有点毫无意义),所以它可以检索磁盘中的数据按排序顺序返回并返回。您的哈希必须通过将所有元素相互比较来进行排序,因此应该更慢。在少量数据上可能不明显,但如果可能的话,应该首选在数据库级别进行排序。不过,我不确定没有索引的情况,可能无关紧要。
    • @DaniëlKnippers 如果数据库是 NoSQL(例如 Neo4j)怎么办? OP 没有提出这些限制。有时想太多会限制简单的解决方案。你同意吗?
    • @Bala 我不认为 Rails 实际上支持 Activerecord 模型的 NoSQL 数据库,我相信它只适用于关系数据库。也许有解决方法。此外,我知道有支持索引的 NoSQL 数据库,例如 MongoDB。无论如何,我并不是说您的答案是错误的,只是指出在数据库级别使用 order 很可能相同或更快。
    【解决方案2】:

    可能是……

       <% map = options_for_select(User.all.map {|u| [u.first_name+" "+u.last_name, u.id]}.sort) %>
    

    【讨论】:

    • 该死的,是的...我在括号后尝试了.sort...对不起,rails 新手...谢谢伙计!
    • 根据我的经验(我开始学习 Rails,对 Ruby 毫无头绪……)学习 Ruby 可以解决我们在开发 Rails 应用程序时遇到的大部分问题。所以试试这种方法,它节省了我们很多时间,让我们对 Ruby 更加好奇。
    • 效果很好!是的,我目前正在学习 Lynda 的红宝石课程。问题是有时将方法放置在哪个顺序中似乎很奇怪。即在哪里放置排序..
    • Killerpixler 在使用该行时要小心,就像在您的视图中一样。它有效,但是您同时违反了几个 Rails 最佳实践:) 请参阅this answer
    【解决方案3】:

    您永远不应该对视图使用查询。您应该仅将视图用于演示,以及模型和/或控制器上的所有逻辑。

    另外,尊重Fat Models, Skinny Controllers Best Practice

    在实践中,这可能需要一系列不同类型的重构,但这一切都归结为一个想法:通过移动任何与响应无关的逻辑(例如,设置一个 flash 消息,或选择是否重定向或呈现视图)到模型(而不是控制器),您不仅在可能的情况下促进了重用,而且还使在请求上下文之外测试代码成为可能。

    最后,在这种情况下,最好使用作用域以便以后重用它。

    在用户模型上使用范围,并有一个name 方法:

    class User < ActiveRecord::Base
      scope :order_by_name, ->(first_name, last_name) { order("#{first_name} ASC, #{ last_name} ASC") }
    
      def name
        "#{first_name} #{last_name}"
      end
    end
    

    如果您从users/index 调用您的线路,请创建一个实例变量来加载用户集合,如下所示:

    class UsersController < ApplicationController
      def index
        @users = User.order_by_name
      end
    end
    

    然后您可以像这样使用options_from_collection_for_select 调用视图:

    <% map = options_from_collection_for_select(@users, :id, :name) %>
    

    【讨论】:

      【解决方案4】:

      出于性能原因,我建议您在数据库中同时执行 CONCAT 和 ORDER

      User.select("CONCAT(u.first_name, ' ', u.last_name), u.id").order("u.first_name")
      

      这个User.all.map 可能是您的应用程序的瓶颈

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-01-01
        • 1970-01-01
        • 2014-03-05
        • 2011-07-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多