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

时间:2021-03-30 16:00:24

In my application I need to show a list of songs. Right now I'm doing this:

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

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

Unfortunately, this means that "The Notorious B.I.G" will sort with the T's while I want him to sort with the N's (i.e., I want to ignore articles -- "the", "a", and "an" -- for the purposes of sorting.

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

My first thought was to do this:

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

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

But it doesn't seem to work. Thoughts?

但它似乎没有用。思考?

4 个解决方案

#1


12  

My favorite approach to these kind of problems is to store an extra sort_order column in the database.

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

That way when you have 10000 songs that you would like to page through, you can do that in SQL and avoid having to pull them all back.

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

Its simple to add a before_save filter to keep this column in sync.

添加before_save过滤器以保持此列同步很简单。

The cleanish solution, without schema changes is:

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

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 }

#2


0  

You may be better off doing this in SQL,

你可能最好在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

There is an article describing this in more detail as well.

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

The big benefit over the approach you have laid out is that you're pulling ALL of the records out first which will screw you up in subtle ways both performance and user interface wise (I'm thinking of situations like trying to page through a large set of songs).

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

#3


0  

Your answer seems to be correct but probably u can change it to:

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

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

changed to sub because you only need to change it in the beginning and not the whole string, space changed to \s to indicate a space.

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

you can go to http://www.rubyxp.com/ to test your regex

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

if it's still not working then probably some records are not coming out the way they should? like spaces at the start of the string, nil or blank title, etc...

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

hope it helps =)

希望它有帮助=)

#4


0  

Break it up!

分开来!

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 }

#1


12  

My favorite approach to these kind of problems is to store an extra sort_order column in the database.

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

That way when you have 10000 songs that you would like to page through, you can do that in SQL and avoid having to pull them all back.

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

Its simple to add a before_save filter to keep this column in sync.

添加before_save过滤器以保持此列同步很简单。

The cleanish solution, without schema changes is:

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

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 }

#2


0  

You may be better off doing this in SQL,

你可能最好在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

There is an article describing this in more detail as well.

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

The big benefit over the approach you have laid out is that you're pulling ALL of the records out first which will screw you up in subtle ways both performance and user interface wise (I'm thinking of situations like trying to page through a large set of songs).

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

#3


0  

Your answer seems to be correct but probably u can change it to:

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

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

changed to sub because you only need to change it in the beginning and not the whole string, space changed to \s to indicate a space.

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

you can go to http://www.rubyxp.com/ to test your regex

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

if it's still not working then probably some records are not coming out the way they should? like spaces at the start of the string, nil or blank title, etc...

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

hope it helps =)

希望它有帮助=)

#4


0  

Break it up!

分开来!

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 }