You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Ruby多参数排序Lambda最后一个RSpec测试失败原因咨询

排序Lambda测试失败原因分析

问题背景

希望通过统一的数组对比逻辑创建排序Lambda,示例逻辑如下:

[a.v1, b.v2] <=> [a.v1, b.v2]
[a.v1, b.v2] <=> [-a.v1, b.v2]
[a.v1, b.v2] <=> [a.v1, -b.v2]
[a.v1, b.v2] <=> [-a.v1, -b.v2]

编写RSpec测试验证逻辑时,最后一个测试(按v1升序、v2降序排序)失败。测试代码核心部分:

class Obj
  attr_reader :v1, :v2, :v3

  def initialize(param1, param2, param3)
    @v1 = param1
    @v2 = param2
    @v3 = param3
  end
end

RSpec.describe(Array) do
  let(:o1) { Obj.new(1, 1, 1) }
  let(:o2) { Obj.new(2, 1, 1) }
  let(:o3) { Obj.new(2, 2, 1) }
  let(:o4) { Obj.new(3, 2, 1) }
  let(:objs) { [o1, o2, o3, o4] }

  # 失败的测试用例
  it "sorts by 2 keys, first ascending and second descending" do
    sort_lambda = ->(a, b) { [a.v1, b.v2] <=> [a.v1, -b.v2] }
    result = objs.sort(&sort_lambda)
    expect(result).to eq([o1, o3, o2, o4])
  end
end

失败信息:

Failure/Error: expect(result).to eq([o1, o3, o2, o4])

expected: [#<Obj:0x00007fc2ac112940 @v1=1, @v2=1, @v3=1>, #<Obj:0x00007fc2ac112828 @v1=2, @v2=2, @v3=1>, #<Obj:0x00007fc2ac1128c8 @v1=2, @v2=1, @v3=1>, #<Obj:0x00007fc2ac112788 @v1=3, @v2=2, @v3=1>]
     got: [#<Obj:0x00007fc2ac112788 @v1=3, @v2=2, @v3=1>, #<Obj:0x00007fc2ac112828 @v1=2, @v2=2, @v3=1>, #<Obj:0x00007fc2ac1128c8 @v1=2, @v2=1, @v3=1>, #<Obj:0x00007fc2ac112940 @v1=1, @v2=1, @v3=1>]

失败原因

你写的Lambda逻辑完全错误:

  • 对比数组的第一个元素都是a.v1,意味着无论a和b的v1值差异是什么,第一个元素的对比结果永远为0(相等);
  • 实际起作用的是第二个元素的对比:b.v2 <=> -b.v2,这个结果只和b自身的v2值有关,和a完全无关;
  • 测试数据中v2都是正数,此时b.v2 > -b.v2,对比结果为1,排序算法会判定a应该排在b后面,最终导致整个数组被完全倒序,和预期的v1升序、v2降序逻辑完全不符。

正确的Lambda写法

要实现**v1升序,v2降序**的排序逻辑,需保持对比的对称性:将a的属性放在左边,b的对应属性(降序则取反)放在右边,正确写法如下:

sort_lambda = ->(a, b) { [a.v1, -a.v2] <=> [b.v1, -b.v2] }

或者更贴合Ruby排序常规逻辑的等价写法:

sort_lambda = ->(a, b) { 
  cmp = a.v1 <=> b.v1
  cmp.zero? ? (-a.v2 <=> -b.v2) : cmp
}

这两种写法都能保证:

  1. 优先按v1升序对比,v1值小的元素排在前面;
  2. 当v1值相等时,按v2降序对比,v2值大的元素排在前面。

修改后测试结果会符合预期:[o1, o3, o2, o4]。


内容的提问来源于stack exchange,提问作者Mike Slinn

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 22:45:59