Ruby中如何基于指定属性向结构体数组追加元素,重复时替换旧值
方案1:封装自定义追加方法(保持数组原生结构)
直接封装操作方法,插入新元素前先删除所有同:num的旧元素,再追加新元素即可,逻辑直观无额外依赖:
Gen = Struct.new(:num, :val) arr = [] arr << Gen.new(11, "foo1") arr << Gen.new(12, "foo2") # 自定义追加替换方法,直接修改原数组 def append_or_replace!(arr, new_obj) # 删除所有num属性匹配的旧元素 arr.delete_if { |item| item.num == new_obj.num } # 追加新元素 arr << new_obj end # 测试用例 s1 = Gen.new(12, "foo10") s2 = Gen.new(13, "foo3") append_or_replace!(arr, s1) append_or_replace!(arr, s2) p arr # 输出符合预期:[#<struct Gen num=11, val="foo1">, #<struct Gen num=12, val="foo10">, #<struct Gen num=13, val="foo3">]
方案2:Hash中间存储(适合高频操作场景,性能更优)
如果需要频繁执行追加替换操作,每次遍历数组的O(n)开销过高,可以直接用:num作为Hash的键,结构体作为值,天然支持同键覆盖,需要数组时直接取values即可:
Gen = Struct.new(:num, :val) # 用Hash存储,key为num属性,自动去重 data = {} data[11] = Gen.new(11, "foo1") data[12] = Gen.new(12, "foo2") # 新增元素直接赋值,同key自动覆盖旧值 s1 = Gen.new(12, "foo10") s2 = Gen.new(13, "foo3") data[s1.num] = s1 data[s2.num] = s2 # 转换为数组 arr = data.values p arr # 输出符合预期:[#<struct Gen num=11, val="foo1">, #<struct Gen num=12, val="foo10">, #<struct Gen num=13, val="foo3">]
补充说明
你之前使用uniq会丢失新元素的原因有两个:
- 代码存在属性名错误:你的结构体定义的属性是
num不是number,原写法arr.uniq {|el| el.number}会直接抛出无方法错误 uniq默认保留第一个出现的匹配元素,就算修正属性名,追加新元素后再去重会保留旧值,如果你非要用uniq实现,可以把新元素插在数组头部再去重:arr.unshift(s1).uniq! { |el| el.num },但该方法会打乱数组原有顺序,性能也不如前两种方案,不推荐使用。
内容的提问来源于stack exchange,提问作者Iggy
相关产品推荐
相关产品推荐

