说我有:
a = ["apple", "pear", ["grapes", "berries"], "peach"]
我希望按以下方式排序:
a.sort_by do |f|
f.class == Array ? f.to_s : f
end
我明白了:
[["grapes", "berries"], "apple", "peach", "pear"]
我真正想要按字母顺序排列项目,数组项目在第一个元素上排序:
["apple", ["grapes", "berries"], "peach", "pear"]
或者,最好是,我想:
["apple", "grapes, berries", "peach", "pear"]
如果示例不够清楚,我希望按字母顺序对项目进行排序。
有关如何到达那里的任何建议吗?
到目前为止,我已经尝试了一些东西但似乎无法实现它。感谢。
答案 0 :(得分:3)
我认为这就是你想要的:
a.sort_by { |f| f.class == Array ? f.first : f }
答案 1 :(得分:3)
我愿意
a = ["apple", "pear", ["grapes", "berries"], "peach"]
a.map { |e| Array(e).join(", ") }.sort
# => ["apple", "grapes, berries", "peach", "pear"]
答案 2 :(得分:1)
你真的很亲密。只需将.to_s
切换为.first
。
irb(main):005:0> b = ["grapes", "berries"]
=> ["grapes", "berries"]
irb(main):006:0> b.to_s
=> "[\"grapes\", \"berries\"]"
irb(main):007:0> b.first
=> "grapes"
这是一个有效的方法:
a.sort_by do |f|
f.class == Array ? f.first : f
end
收率:
["apple", ["grapes", "berries"], "peach", "pear"]
答案 3 :(得分:1)
a.map { |b| b.is_a?(Array) ? b.join(', ') : b }.sort
# => ["apple", "grapes, berries", "peach", "pear"]
答案 4 :(得分:1)
将to_s
替换为join
。
a.sort_by do |f|
f.class == Array ? f.join : f
end
# => ["apple", ["grapes", "berries"], "peach", "pear"]
或者更简洁:
a.sort_by {|x| [*x].join }
# => ["apple", ["grapes", "berries"], "peach", "pear"]
to_s
的问题在于它将您的数组转换为以"["
开头的字符串:
"[\"grapes\", \"berries\"]"
在其余字符串之前按字母顺序排列。
join
实际上创建了您希望排序的字符串:
"grapesberries"
根据你的逻辑正确地按字母顺序排列。
如果您不希望数组保留数组,那么操作稍有不同,但您仍然会使用join
。
a.map {|x| [*x].join(", ") }.sort
# => ["apple", "grapes, berries", "peach", "pear"]
答案 5 :(得分:1)
Array#sort_by显然是正确的方法,但这里提醒一下Array#sort如何在这里使用:
a.sort do |s1,s2|
t1 = (s1.is_a? Array) ? s1.first : s1
t2 = (s2.is_a? Array) ? s2.first : s2
t1 <=> t2
end.map {|e| (e.is_a? Array) ? e.join(', ') : e }
#=> ["apple", "grapes, berries", "peach", "pear"]
@theTinMan指出sort
比sort_by
慢得多,并给出了解释原因的参考。我一直想知道如何使用Benchmark module,所以借此机会比较手头问题的两种方法。我使用@ Rafa的解决方案sort_by
和我的sort
。
为了进行测试,我提前构建了一个包含100个随机样本(每个样本有10,000个随机元素)的数组,因此基准测试不包括构建样本所需的时间(这并不是无关紧要的)。 10,000个元素中的8,000个是8个小写字母的随机字符串。其他2,000个元素是[str1, str2]
形式的2元组,其中str1
和str2
都是8个小写字母的随机字符串。我使用其他参数进行基准测试,但底线结果没有显着变化。
require 'benchmark'
# n: total number of items to sort
# m: number of two-tuples [str1, str2] among n items to sort
# n-m: number of strings among n items to sort
# k: length of each string in samples
# s: number of sorts to perform when benchmarking
def make_samples(n, m, k, s)
s.times.with_object([]) { |_, a| a << test_array(n,m,k) }
end
def test_array(n,m,k)
a = ('a'..'z').to_a
r = []
(n-m).times { r << a.sample(k).join }
m.times { r << [a.sample(k).join, a.sample(k).join] }
r.shuffle!
end
# Here's what the samples look like:
make_samples(6,2,4,4)
#=> [["bloj", "izlh", "tebz", ["lfzx", "rxko"], ["ljnv", "tpze"], "ryel"],
# ["jyoh", "ixmt", "opnv", "qdtk", ["jsve", "itjw"], ["pnog", "fkdr"]],
# ["sxme", ["emqo", "cawq"], "kbsl", "xgwk", "kanj", ["cylb", "kgpx"]],
# [["rdah", "ohgq"], "bnup", ["ytlr", "czmo"], "yxqa", "yrmh", "mzin"]]
n = 10000 # total number of items to sort
m = 2000 # number of two-tuples [str1, str2] (n-m strings)
k = 8 # length of each string
s = 100 # number of sorts to perform
samples = make_samples(n,m,k,s)
Benchmark.bm('sort_by'.size) do |bm|
bm.report 'sort_by' do
samples.each do |s|
s.sort_by { |f| f.class == Array ? f.first : f }
end
end
bm.report 'sort' do
samples.each do |s|
s.sort do |s1,s2|
t1 = (s1.is_a? Array) ? s1.first : s1
t2 = (s2.is_a? Array) ? s2.first : s2
t1 <=> t2
end
end
end
end
user system total real
sort_by 1.360000 0.000000 1.360000 ( 1.364781)
sort 4.050000 0.010000 4.060000 ( 4.057673)
虽然从未有过怀疑,但是@theTinMan是对的!我使用不同的参数进行了一些其他运行,但sort_by
始终以相似的性能比率重击sort
。
请注意sort_by
的“系统”时间为零。在其他运行中,sort
有时为零。值始终为零或0.010000
,让我想知道那里发生了什么。 (我在Mac上运行这些。)
对于不熟悉Benchmark
的读者,Benchmark#bm采用的参数等于标题行(user system...
)所需的左填充量。 bm.report
将行标签作为参数。
答案 6 :(得分:0)