在Ruby中对数组进行排序忽略文章(“the”,“a”,“an”)

在我的应用程序中,我需要显示一个歌曲列表。 现在我这样做:

Song.all.sort {|x,y| x.artist.name  y.artist.name } 

不幸的是,这意味着“The Notorious BIG”将与T一起排序,而我希望他与N一起排序(即,我想忽略文章 – “the”,“a”和“an” – 对于排序的目的。

我的第一个想法是这样做:

 Song.all.sort {|x,y| x.artist.name.gsub(/^(the|a|an) /i, '')  y.artist.name.gsub(/^(the|a|an) /i, '') } 

但它似乎没有用。 思考?

我最喜欢的解决这类问题的方法是在数据库中存储一个额外的 sort_order列。

这样,当你想要翻阅10000首歌曲时,可以在SQL中执行此操作,避免将其全部拉回来。

添加before_savefilter以保持此列同步很简单。

没有架构更改的清洁解决方案是:

 class Artist def sortable_name self.name.sub(/^(the|a|an)\s+/i, '') end end class Song def sortable_name # note the - is there so [Radio] [head on] and [Radiohead] [karma police] # are not mixed in the ordering "#{artist.sortable_name} - #{name}" end end # breaks ties as well Song.all.sort_by { |song| song.sortable_name } 

你可能最好在SQL中这样做,

 SELECT Title, CASE WHEN SUBSTRING_INDEX(Title, ' ', 1) IN ('a', 'an', 'the') THEN CONCAT( SUBSTRING(Title, INSTR(Title, ' ') + 1), ', ', SUBSTRING_INDEX(Title, ' ', 1) ) ELSE Title END AS TitleSort FROM music ORDER BY TitleSort 

还有一篇文章更详细地描述了这一点。

你所提出的方法的最大好处是你首先将所有记录都拉出来,这将使你在性能和用户界面方面都有微妙的方式(我想到的是尝试翻阅大片的情况)一组歌曲)。

你的答案似乎是正确的,但可能你可以改为:

 Song.all.sort {|x, y| x.artist.name.sub(/^(the|a|an)\s/i, '') <=> y.artist.name.sub(/^(the|a|an)\s/i, '') } 

更改为sub,因为您只需要在开头而不是整个字符串中更改它,将空格更改为\ s以指示空格。

你可以去http://www.rubyxp.com/来测试你的正则表达式

如果它仍然没有工作,那么可能有些记录不会以他们应该的方式出现? 像字符串开头的空格,零或空白标题等…

希望它有帮助=)

分开来!

 class Artist < ActiveRecord::Base def <=>(other) name.gsub(/^(the|a|an) /i, '') <=> other.name.gsub(/^(the|a|an) /i, '') end end songs = Song.all(:include => :artist) songs.sort_by { |s| s.artist }