按一组参数对 Ruby 数组进行排序,回退到下一个参数,以防它未定义
Sort Ruby array by a set of parameters, fall back to next parameter in case it's undefined
在 Ruby 中,根据可能存在或不存在的 order
属性对对象数组进行排序的最佳方法是什么?如果不存在,则回退到基于名为 title
?
的属性
你可以试试
def sort_array(array)
sort_by_property_name = sort_by_property_present?(array, :order, :title)
array.sort_by { |ob| ob.public_send(sort_by_property_name) }
end
def sort_by_property_present?(array, primary_name, fallback_name)
array.all? { |ob| ob.respond_to?(name) } || return fallback_name
primary_name
end
如果我明白你是怎么做的:
arr1 = [{order: 1, title: 2},{title: 4},{order: 2, title: 1}]
arr2 = [{order: 1, title: 2},{order: 7, title: 4},{order: 2, title: 1}]
def sort_it prop1, prop2, ar
ar.map{|el| el[prop1]}.include?(nil) ?
ar.sort_by{|el| el[prop2]}
:
ar.sort_by{|el| el[prop1]}
end
p sort_it(:order, :title, arr1)
p sort_it(:order, :title, arr2)
给出:
#=> [{:order=>2, :title=>1}, {:order=>1, :title=>2}, {:title=>4}]
#=> [{:order=>1, :title=>2}, {:order=>2, :title=>1}, {:order=>7, :title=>4}]
所以,算法很简单:select 所有对象的属性(在我们的例子中是 :order
),如果输出临时数组至少包含一个 nil
,则按给定的秒排序属性,否则 -- 首先。
不确定这是否是您想要的,但一个快速的解决方案可能是:
arr = [{a:"never", b:"anna"}, {a:"always", b:"bob"}, {b:"colin"}, {b:"abe"}]
arr.sort_by! {|o| o[:a] ? o[:a] : o[:b] }
#=> [{:b=>"abe"}, {:a=>"always", :b=>"bob"}, {:b=>"colin"}, {:a=>"never", :b=>"anna"}]
以下是如何在 Ruby 中使用回退执行排序:
Item = Struct.new(:order, :title)
items = [
Item.new(nil, "d"),
Item.new(nil, "b"),
Item.new(1, "a"),
Item.new(3, "c"),
Item.new(2, "e")
]
sorted_items = items.sort do |a, b|
if a.order && b.order
a.order <=> b.order
elsif a.order || b.order
# This prioritizes all items with an order
a.order ? -1 : 1
else
a.title.to_s <=> b.title.to_s
end
end
require 'awesome_print'
ap sorted_items
# [
# [0] {
# :order => 1,
# :title => "a"
# },
# [1] {
# :order => 2,
# :title => "e"
# },
# [2] {
# :order => 3,
# :title => "c"
# },
# [3] {
# :order => nil,
# :title => "b"
# },
# [4] {
# :order => nil,
# :title => "d"
# }
# ]
我还要说一下,如果您要从数据库中获取记录,那么最好在 SQL 查询中进行排序。如果 Item
是一个 ActiveRecord 模型,你可以这样做:
Item.order('order ASC NULLS LAST, title ASC')
(NULLS LAST can be used in Postgres, check out this answer for MySQL.)
假设您想根据可能存在或不存在的 field/parameter 进行排序,我假设:
- 当参数存在时按它排序。
- 当不可用时回退到下一个参数。
请查看以下代码,它可以根据多个字段对对象数组进行排序,如果该字段不可用,系统会不断回退到下一个字段。它是在最后一个字段肯定存在的假设下开发的。
class CondtionalSort
def run(array: a, keys_to_order_by: keys)
array.sort do |e1, e2|
keys_to_order_by.each do |key|
break e1[key] <=> e2[key] if (e1.key?(key) && e2.key?(key))
end
end
end
end
ArrayTest = [{order: 1, title: 2},{title: 4},{order: 2, title: 1}]
ArrayTest_SORTED = [{:order=>1, :title=>2}, {:order=>2, :title=>1}, {:title=>4}]
sorter = CondtionalSort.new
sorter.run array: ArrayTest, keys_to_order_by: [:order, :title]
我只是使用数组作为 sort_by:
# sample data:
Item = Struct.new(:property1, :property2, :property3)
collection = [Item.new("thing1", 3, 6), Item.new("thing1", 3, 1), Item.new("aaa", 1,1) ]
# sort
collection.sort_by{|item| [item.property1, item.property2, item.property3] }
# => [#<struct Item property1="aaa", property2=1, property3=1>,
#<struct Item property1="thing1", property2=3, property3=1>,
#<struct Item property1="thing1", property2=3, property3=6>]
在 Ruby 中,根据可能存在或不存在的 order
属性对对象数组进行排序的最佳方法是什么?如果不存在,则回退到基于名为 title
?
你可以试试
def sort_array(array)
sort_by_property_name = sort_by_property_present?(array, :order, :title)
array.sort_by { |ob| ob.public_send(sort_by_property_name) }
end
def sort_by_property_present?(array, primary_name, fallback_name)
array.all? { |ob| ob.respond_to?(name) } || return fallback_name
primary_name
end
如果我明白你是怎么做的:
arr1 = [{order: 1, title: 2},{title: 4},{order: 2, title: 1}]
arr2 = [{order: 1, title: 2},{order: 7, title: 4},{order: 2, title: 1}]
def sort_it prop1, prop2, ar
ar.map{|el| el[prop1]}.include?(nil) ?
ar.sort_by{|el| el[prop2]}
:
ar.sort_by{|el| el[prop1]}
end
p sort_it(:order, :title, arr1)
p sort_it(:order, :title, arr2)
给出:
#=> [{:order=>2, :title=>1}, {:order=>1, :title=>2}, {:title=>4}]
#=> [{:order=>1, :title=>2}, {:order=>2, :title=>1}, {:order=>7, :title=>4}]
所以,算法很简单:select 所有对象的属性(在我们的例子中是 :order
),如果输出临时数组至少包含一个 nil
,则按给定的秒排序属性,否则 -- 首先。
不确定这是否是您想要的,但一个快速的解决方案可能是:
arr = [{a:"never", b:"anna"}, {a:"always", b:"bob"}, {b:"colin"}, {b:"abe"}]
arr.sort_by! {|o| o[:a] ? o[:a] : o[:b] }
#=> [{:b=>"abe"}, {:a=>"always", :b=>"bob"}, {:b=>"colin"}, {:a=>"never", :b=>"anna"}]
以下是如何在 Ruby 中使用回退执行排序:
Item = Struct.new(:order, :title)
items = [
Item.new(nil, "d"),
Item.new(nil, "b"),
Item.new(1, "a"),
Item.new(3, "c"),
Item.new(2, "e")
]
sorted_items = items.sort do |a, b|
if a.order && b.order
a.order <=> b.order
elsif a.order || b.order
# This prioritizes all items with an order
a.order ? -1 : 1
else
a.title.to_s <=> b.title.to_s
end
end
require 'awesome_print'
ap sorted_items
# [
# [0] {
# :order => 1,
# :title => "a"
# },
# [1] {
# :order => 2,
# :title => "e"
# },
# [2] {
# :order => 3,
# :title => "c"
# },
# [3] {
# :order => nil,
# :title => "b"
# },
# [4] {
# :order => nil,
# :title => "d"
# }
# ]
我还要说一下,如果您要从数据库中获取记录,那么最好在 SQL 查询中进行排序。如果 Item
是一个 ActiveRecord 模型,你可以这样做:
Item.order('order ASC NULLS LAST, title ASC')
(NULLS LAST can be used in Postgres, check out this answer for MySQL.)
假设您想根据可能存在或不存在的 field/parameter 进行排序,我假设:
- 当参数存在时按它排序。
- 当不可用时回退到下一个参数。
请查看以下代码,它可以根据多个字段对对象数组进行排序,如果该字段不可用,系统会不断回退到下一个字段。它是在最后一个字段肯定存在的假设下开发的。
class CondtionalSort
def run(array: a, keys_to_order_by: keys)
array.sort do |e1, e2|
keys_to_order_by.each do |key|
break e1[key] <=> e2[key] if (e1.key?(key) && e2.key?(key))
end
end
end
end
ArrayTest = [{order: 1, title: 2},{title: 4},{order: 2, title: 1}]
ArrayTest_SORTED = [{:order=>1, :title=>2}, {:order=>2, :title=>1}, {:title=>4}]
sorter = CondtionalSort.new
sorter.run array: ArrayTest, keys_to_order_by: [:order, :title]
我只是使用数组作为 sort_by:
# sample data:
Item = Struct.new(:property1, :property2, :property3)
collection = [Item.new("thing1", 3, 6), Item.new("thing1", 3, 1), Item.new("aaa", 1,1) ]
# sort
collection.sort_by{|item| [item.property1, item.property2, item.property3] }
# => [#<struct Item property1="aaa", property2=1, property3=1>,
#<struct Item property1="thing1", property2=3, property3=1>,
#<struct Item property1="thing1", property2=3, property3=6>]