我如何在红宝石中按不等排序?



我看到这篇文章使用排序比较器,但我如何按不等排序

Ruby 的 <=> 运算符和排序方法

我有一条短信

猫 猫 猫 猫 猫 狗 狗 狗 狗 狗 叠 叠 叠 叠 叠 星 星 星 星 星 列表 列表 列表 列表

当 B1 等于 B2 时,使用逻辑列出 将 B2 放在最后,但当 B1 不等于 B2 时,将 B2 放在 B1 旁边

对于获得

猫 狗 叠 星 列表 猫 狗 叠 星 列表 猫 狗 叠 星 列表 猫 狗 叠 星 列表 猫 狗 叠 星 列表

请帮我解决这个问题

如果您的数组具有均匀分布的元素(不一定排序(。

arr = ['a','a','a','b','b','b','c','c','c']
arr.uniq * arr.uniq.size #=> ["a", "b", "c", "a", "b", "c", "a", "b", "c"]

警告:如果未排序,则在uniq期间遇到的第一个唯一元素将确定最终的数组排序。

除了评论之外,这里有一个更强大的解决方案:

arr = ['a','a','a','b','b','b','c','c','c','d','d','d']
enum = arr.uniq.cycle
enum.take(arr.size)
#=> ["a", "b", "c", "d", "a", "b", "c", "d", "a", "b", "c", "d"]

我没有看到使用<=>比较的解决方案。

但这里有一种方法可以做到这一点:

使用Enumerable#chunk可以将相同的值组合在一起(如果数组已排序;否则可以使用group_by(。

然后,选择根据其值拆分的组,并转置该数组并将值重新连接在一起。

长话短说

array.chunk{ |a| a }.map{ |k, v| v }.transpose.flatten

将为示例中的数据做正确的事情。

请注意,为了使transpose正常工作,组必须包含相同数量的元素。

编辑:

这是 engineersmnky 在评论中建议的更好版本,即使组的大小不同,它也可以工作:

array.chunk(&:itself).map(&:last).inject { |memo, e| memo.zip(e) }.flatten

你可以做:

arr.group_by {|w| w}.values.transpose.flatten

这仅在所有组具有相同数量的单词时才有效。如果您的组没有相同数量的单词,则不清楚您要查找的内容。

如果希望由最短长度的组定义组,可以执行以下操作:

na=arr.group_by {|w| w}.values
len=na.map {|l| l.length}.min
na.map {|l| l[0...len] }.transpose.flatten

如果你想使用sort算法,你可能想做一些类似于装饰、排序、非装饰(又名 DSU 或 Schwartzian 变换(的事情,如下所示:

> arr=['cat']*4+['dog']*3+['list']*2+["star"]
> arr.group_by {|w| w}                     # all same words together
.values                              # only the sepate lists of words
.map {|l| l.each_with_index          # enumerate those so that we have [0, word]..[n, word]
.map {|e,i| [i,e]}}.flatten(1)       # remove one level of nesting
.sort                                # sort first on the number then on the word
.map {|l| l[1]}                      # remove the number
["cat", "dog", "list", "star", "cat", "dog", "list", "cat", "dog", "cat"]

这将允许不同长度的词组,较长的组最终位于数组的前面。

要满足请求的实际逻辑:

当 B1 等于 B2 时,

使用逻辑将 B2 放在最后,但当 B1 不等于 B2 时,将 B2 放在 B1 旁边

你可以使用老式的递归

def process(arr)
arr.each_with_index.each_cons(2) do |a,b| 
if a.first == b.first then 
arr << arr.delete_at(b.last)
process(arr)
end
end
arr
end

此方法完全按照所述执行。如果a == bb移动到列表的末尾,并重新处理整个列表,直到没有a == b事件

另一种解决方案,它将输出列表长度基于列表中出现最少的元素,并且只要唯一元素在列表中的位置是可接受的排序,就不需要排序

def repeat_unordered_list(arr)
arr.group_by(&:itself).to_a.tap do |a|
min_elements = a.min_by{|_,v| v.size}.last.size
a.replace(a.map(&:first) * min_elements)
end
end 

示例

最新更新