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

Ruby项目中简化获取对象数组属性最高/最低出现次数的方法

Ruby项目:简化获取最多/最少访问港口名称的函数

我正在开发Ruby项目,需要从FleetShip对象数组中分别获取指定日期下,出现次数最多、最少的ending_port对应的名称。目前功能已实现,但代码过于冗长,希望找到更简洁的实现方式。

现有代码

def most_visited_port(time)

    most_visited_port_name = ""
    most_visited = 0
    ending_port_array = []

    @ships.each do |ship|
        ending_port_array << ship.ending_port
        most_visited = ending_port_array.sort.max_by { |v| ending_port_array.count(v) } != ending_port_array.sort.reverse.max_by { |v| ending_port_array.count(v) } ? false : ending_port_array.max_by { |v| ending_port_array.count(v) }
    end


    @ships.each do |ship|
        if time.to_date === ship.time_arrived.to_date && ship.ending_port == most_visited
            most_visited_port_name = ship.ending_port_name
        end
    end

    pp most_visited_port_name

end

def least_visited_port(time)
    least_visited_port_name = ""
    least_visited = 0
    ending_port_array = []

    @ships.each do |ship|
        ending_port_array << ship.ending_port
        least_visited = ending_port_array.sort.min_by { |v| ending_port_array.count(v) } != ending_port_array.sort.reverse.min_by { |v| ending_port_array.count(v) } ? false : ending_port_array.min_by { |v| ending_port_array.count(v) }
    end


    @ships.each do |ship|
        if time.to_date === ship.time_arrived.to_date && ship.ending_port == least_visited
            least_visited_port_name = ship.ending_port_name
        end
    end

    pp least_visited_port_name
end

FleetShip对象数组示例

[#<FleetShip:0x0000000108444450
  @average_speed=46.02272727272727,
  @beginning_port=7,
  @beginning_port_name="Summermill",
  @distance=81.0,
  @ending_port=3,
  @ending_port_name="Seamont",
  @id=0,
  @ship_name="Alpha",
  @time_arrived=2016-06-12 08:05:36 -0500,
  @time_left=2016-06-12 06:20:00 -0500>,
 #<FleetShip:0x0000000108444400
  @average_speed=32.01932579334578,
  @beginning_port=7,
  @beginning_port_name="Summermill",
  @distance=81.0,
  @ending_port=3,
  @ending_port_name="Seamont",
  @id=1,
  @ship_name="Sea Ghost",
  @time_arrived=2016-06-12 11:07:47 -0500,
  @time_left=2016-06-12 08:36:00 -0500>]

优化方案

核心思路

  1. 先筛选出指定日期的船只,避免处理无关数据
  2. 用Ruby内置方法高效统计端口出现次数,替代手动遍历计数
  3. 提取通用逻辑,消除两个方法的代码重复
  4. 处理空数据、并列端口等边界情况

优化后代码

# 通用方法:获取指定日期下访问次数最多/最少的港口名称
# mode 参数传入 :most 或 :least
def visited_port_name(time, mode)
  # 筛选出当日到港的船只
  daily_ships = @ships.select { |ship| ship.time_arrived.to_date == time.to_date }
  return nil if daily_ships.empty?

  # 统计每个ending_port的出现次数(Ruby 2.7+ 可用tally,低版本用注释里的写法)
  port_counts = daily_ships.tally { |ship| ship.ending_port }
  # 兼容Ruby 2.7以下版本:
  # port_counts = daily_ships.group_by { |ship| ship.ending_port }.transform_values(&:size)

  # 根据模式找到目标端口
  target_port = case mode
                when :most
                  port_counts.max_by { |_port, count| count }&.first
                when :least
                  port_counts.min_by { |_port, count| count }&.first
                end

  # 返回对应的港口名称
  daily_ships.find { |ship| ship.ending_port == target_port }&.ending_port_name
end

# 获取最多访问港口名称
def most_visited_port(time)
  pp visited_port_name(time, :most)
end

# 获取最少访问港口名称
def least_visited_port(time)
  pp visited_port_name(time, :least)
end

处理并列端口的扩展

如果需要返回所有并列的港口名称(比如多个港口访问次数相同且都是最多/最少),可以修改通用方法:

def visited_port_names(time, mode)
  daily_ships = @ships.select { |ship| ship.time_arrived.to_date == time.to_date }
  return [] if daily_ships.empty?

  port_counts = daily_ships.tally { |ship| ship.ending_port }
  target_count = case mode
                 when :most then port_counts.values.max
                 when :least then port_counts.values.min
                 end

  target_ports = port_counts.select { |_port, count| count == target_count }.keys
  # 去重后返回所有对应名称
  daily_ships.select { |ship| target_ports.include?(ship.ending_port) }.map(&:ending_port_name).uniq
end

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.22 18:48:38