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

基于Barn轮换复用的农场需求计算(TypeScript实现问题)

问题描述

我有一份包含200-300条记录的XLSX文件,记录格式如下:

DateBarns
14/May/202413
15/May/202414
16/May/202416

每条记录代表孵化场每日产出鸡群对应的Barn数量(每座Barn容纳33000只鸡)。已将数据转换为JSON并存入数据库,现需计算容纳这些鸡群所需的农场数量。

规则说明:

  • 每个农场可容纳16座Barn;
  • 每座Barn饲养鸡群33天后售出,售出后需空置22天才能再次使用(即56天后可复用)。

当前TypeScript代码未考虑Barn 56天后可复用的规则,仅在农场填满时持续新增农场,无法准确计算所需农场数量,现有代码如下:

const settings = { BARNS_PER_FARM: 16 }

const totalBarns = planDays.reduce((acc, day) => acc + day.barns, 0)
const firstDate = planDays[0]?.date
const lastDate = planDays[planDays.length - 1]?.date
const farmsNeeded = Math.ceil(totalBarns / settings.BARNS_PER_FARM)

const copy = [...planDays]

const farms: Farm[] = Array.from({ length: farmsNeeded }).map((_, i) => {
  return {
    name: `Farm ${i + 1}`,
    housing: [],
    lastUsedDate: null, // Track last used date for reusability
  }
})

const current = {
  farm: 0,
}

for (const day of copy) {
  const barns = day.barns
  if (barns === 0) {
    continue
  }

  const farm = farms[current.farm]

  const available = settings.BARNS_PER_FARM - farmUsedBarns(farm)

  const needed = barns

  if (available >= needed) {
    addHousing(farm, needed, day.date)
  }
  else {
    if (available > 0) {
      addHousing(farm, available, day.date)
    }

    let remaining = needed - available
    while (remaining > 0) {
      current.farm++
      const farm = farms[current.farm]
      const available = settings.BARNS_PER_FARM - farmUsedBarns(farms[current.farm])

      const needed = remaining
      if (available >= needed) {
        addHousing(farm, needed, day.date)
        remaining = 0
      }
      else {
        addHousing(farm, available, day.date)
        remaining -= available
      }
    }
  }
}

return {
  status: 200,
  body: {
    data: {
      farms: farms.filter(farm => farm.housing.length > 0),
      totalBarns,
      firstDate,
      lastDate,
      farmsNeeded,
    },
  },
}

function addHousing(farm: Farm, numberOfBarns: number, startDate: Date) {
  if (farm.housing.length === 0) {
    farm.housing.push({
      name: 'A',
      startDate: startDate,
      numberOfBarns,
    })
    return
  }
  const previousHousing = farm.housing[farm.housing.length - 1]
  const newStartDate = new Date(previousHousing.startDate)
  newStartDate.setDate(newStartDate.getDate() + 1)

  farm.housing.push({
    name: String.fromCharCode(previousHousing.name.charCodeAt(0) + 1),
    numberOfBarns,
    startDate: startDate,
  })
}

function farmUsedBarns(farm: Farm) {
  return farm.housing.reduce((acc, housing) => {
    return acc + housing.numberOfBarns
  }, 0)
}
优化方案

核心思路

  • 跟踪Barn可用时间:给每个农场的批次记录添加endDate(即该批次Barn可再次使用的日期,startDate + 56天),用于判断当前日期是否有可用Barn;
  • 优先复用现有容量:每日分配Barn时,先遍历所有已创建的农场,统计可用Barn数量,优先使用这些容量;
  • 动态创建农场:当现有农场可用容量总和无法满足当日需求时,再新建农场补充剩余需求;
  • 精准统计农场数:不再提前预估农场数量,而是根据实际分配结果统计最终使用的农场总数。

优化后的完整代码

// 定义类型确保类型安全
type HousingRecord = {
  name: string;
  startDate: Date;
  endDate: Date; // 新增:Barn可复用的日期
  numberOfBarns: number;
};

type Farm = {
  name: string;
  housing: HousingRecord[];
};

const settings = {
  BARNS_PER_FARM: 16,
  BARN_REUSE_DAYS: 56, // 33天饲养 + 22天空置
};

export function calculateRequiredFarms(planDays: { date: Date; barns: number }[]) {
  const totalBarns = planDays.reduce((acc, day) => acc + day.barns, 0);
  const firstDate = planDays[0]?.date;
  const lastDate = planDays[planDays.length - 1]?.date;
  const farms: Farm[] = [];

  // 计算单个农场在指定日期的可用Barn数量
  const getAvailableBarnsForFarm = (farm: Farm, currentDate: Date): number => {
    const usedBarns = farm.housing.reduce((acc, housing) => {
      // 当前日期早于endDate时,Barn仍处于占用状态
      return currentDate < housing.endDate ? acc + housing.numberOfBarns : acc;
    }, 0);
    return settings.BARNS_PER_FARM - usedBarns;
  };

  // 为农场添加批次记录,自动生成名称和endDate
  const addHousingBatch = (farm: Farm, numberOfBarns: number, startDate: Date) => {
    const nextName = farm.housing.length === 0 
      ? 'A' 
      : String.fromCharCode(farm.housing[farm.housing.length - 1].name.charCodeAt(0) + 1);
    const endDate = new Date(startDate);
    endDate.setDate(endDate.getDate() + settings.BARN_REUSE_DAYS);

    farm.housing.push({
      name: nextName,
      startDate,
      endDate,
      numberOfBarns,
    });
  };

  for (const day of planDays) {
    let remainingBarns = day.barns;
    if (remainingBarns <= 0) continue;

    // 1. 优先使用已有农场的可用Barn
    for (const farm of farms) {
      if (remainingBarns <= 0) break;
      const available = getAvailableBarnsForFarm(farm, day.date);
      if (available <= 0) continue;

      const useCount = Math.min(available, remainingBarns);
      addHousingBatch(farm, useCount, day.date);
      remainingBarns -= useCount;
    }

    // 2. 剩余需求新建农场
    while (remainingBarns > 0) {
      const newFarm: Farm = {
        name: `Farm ${farms.length + 1}`,
        housing: [],
      };
      farms.push(newFarm);

      const available = settings.BARNS_PER_FARM;
      const useCount = Math.min(available, remainingBarns);
      addHousingBatch(newFarm, useCount, day.date);
      remainingBarns -= useCount;
    }
  }

  // 过滤未使用的农场
  const usedFarms = farms.filter(farm => farm.housing.length > 0);

  return {
    status: 200,
    body: {
      data: {
        farms: usedFarms,
        totalBarns,
        firstDate,
        lastDate,
        farmsNeeded: usedFarms.length, // 实际所需农场数
      },
    },
  };
}

关键改进点

  • 新增endDate字段精准跟踪Barn复用时间,替代原有的模糊lastUsedDate;
  • getAvailableBarnsForFarm函数实时计算农场可用容量,避免累计统计的误差;
  • 分配逻辑改为先复用再新建,大幅减少不必要的农场数量;
  • 动态计算实际所需农场数,结果更贴合业务规则。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 21:24:52