ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

freeCodeCamp 每日编程挑战 269 实战:用 JavaScript 的 filter + some 实现 Allergen Friendly Meals 过敏源筛选

freeCodeCamp 每日编程挑战 269 实战:用 JavaScript 的 filter + some 实现 Allergen Friendly Meals 过敏源筛选 freeCodeCamp 每日编程挑战 269 实战用 JavaScript 的 filter some 实现 Allergen Friendly Meals 过敏源筛选【免费下载链接】freeCodeCampfreeCodeCamp.orgs open-source codebase and curriculum. Learn math, programming, and computer science for free.项目地址: https://gitcode.com/GitHub_Trending/fr/freeCodeCamp本指南以 freeCodeCamp 开源仓库中 daily-coding-challenges-javascript 板块的Challenge 269: Allergen Friendly Meals原题文档为核心完整拆解题目规格、四组官方测试用例、算法设计思路与官方参考解法并联动仓库中的 API 路由、TypeBox 响应 schema 与日期工具源码讲清这道题在真实系统中的来龙去脉。读完本文你将掌握双重数组过滤类题目的标准解法范式filter与some的配合、includes的成员判断并了解 freeCodeCamp 每日挑战从前端题目到后端 API 的完整技术链路。一、挑战背景freeCodeCamp 的每日编程挑战体系Challenge 269 属于 freeCodeCamp 仓库中curriculum目录下的Daily Coding Challenges每日编程挑战板块共 365 道题按日期每天一道。该板块的元数据定义在 curriculum/structure/blocks/daily-coding-challenges-javascript.json 中其中 Challenge 269 的条目第 1081–1084 行如下{ id: 69cfca90e8a0a6d4d6871c53, title: Challenge 269: Allergen Friendly Meals }从同一结构文件的顶部可以看到该板块的关键配置isUpcomingChange: true属于新推出的板块helpCategory: JavaScript归入 JavaScript 学习分类usesMultifileEditor: true使用多文件编辑器作答disableLoopProtectTests: true关闭循环保护测试允许自由使用循环。在运行时层面freeCodeCamp 的 API 为每日挑战提供了公开只读接口定义于 api/src/daily-coding-challenge/routes/daily-coding-challenge.ts包括GET /daily-coding-challenge/date/:date、GET /daily-coding-challenge/today、GET /daily-coding-challenge/month/:month、GET /daily-coding-challenge/all等端点挑战的提交仍然走主 API 的挑战完成路由。也就是说这道题既是学习者日常刷题的对象也是后端每日定时更新内容的一部分。二、题目规格Allergen Friendly Meals 需求拆解原题文档69cfca90e8a0a6d4d6871c53.md给出的任务描述为Given an array of meals and an array of allergens to avoid, return the names of all the meals that contain none of the given allergens.即给定一份菜品数组和一份需要回避的过敏原数组返回所有不含任何指定过敏原的菜品名称。2.1 输入数据格式题目明确规定了两种输入的数据结构输入格式示例meals二维数组每个元素为[meal, allergens]meal是菜品名称字符串allergens是该菜品包含的过敏原字符串数组[pasta, [wheat, milk]]allergens需要回避的过敏原字符串数组[milk]2.2 输出要求返回安全菜品名称组成的数组输出顺序必须与输入meals中的原始顺序一致若没有任何安全菜品返回空数组[]菜品自身过敏原数组为[]时即无过敏原的菜只要回避列表非空必为安全菜——这一点在后面的测试用例 2 中有直接体现fried rice, []。2.3 边界与隐含规则交集判定一道菜不安全当且仅当菜品过敏原数组与回避过敏原数组存在至少一个共同元素交集非空。空回避列表若allergens为空数组some循环不会执行所有菜品无论是否含过敏原都将被判定为安全并返回——这是Array.prototype.some在空数组上恒返回false的自然结果。字符串精确匹配过敏原按字符串全等比较不区分大小写、不做模糊匹配。三、官方测试用例全解Hints原题提供了四组由assert.deepEqual断言的测试用例即挑战平台上的 hints覆盖了部分命中全部命中多过敏原交叉无过敏原菜品等典型场景。以下逐一拆解测试 1单个过敏原部分菜品命中assert.deepEqual( getAllergenFriendlyMeals( [[pasta, [wheat, milk]], [salad, [nuts]]], [milk] ), [salad] );pasta含milk命中回避列表被剔除salad只含nuts不在回避列表中安全保留。测试 2多个过敏原 无过敏原菜品assert.deepEqual( getAllergenFriendlyMeals( [ [steak, [soy]], [fried rice, []], [fish tacos, [fish, wheat]], [chicken parmesan, [wheat, milk]] ], [soy, fish] ), [fried rice, chicken parmesan] );steak含soy被剔除fish tacos含fish被剔除fried rice过敏原为空数组天然安全chicken parmesan含wheat、milk均不在回避列表[soy, fish]中安全保留。注意输出顺序[fried rice, chicken parmesan]与输入顺序完全一致。测试 3重叠过敏原集合验证任一命中即剔除assert.deepEqual( getAllergenFriendlyMeals( [ [oatmeal, [nuts]], [pancakes, [wheat, milk]], [granola, []], [yogurt, [milk]], [eggs, [eggs, milk]], [toast, [wheat]] ], [eggs, milk] ), [oatmeal, granola, toast] );回避列表为[eggs, milk]。pancakes含milk剔除yogurt含milk剔除eggs的过敏原数组[eggs, milk]同时命中两个回避项剔除oatmealnuts、granola空、toastwheat均不含eggs/milk安全保留。此用例验证了命中任意一个回避过敏原即剔除的规则。测试 4换一组回避列表结果随之翻转assert.deepEqual( getAllergenFriendlyMeals( [ [oatmeal, [nuts]], [pancakes, [wheat, milk]], [granola, []], [yogurt, [milk]], [eggs, [eggs, milk]], [toast, [wheat]] ], [wheat, nuts] ), [granola, yogurt, eggs] );同样的菜品数据回避列表换成[wheat, nuts]后oatmealnuts、pancakeswheat、toastwheat被剔除granola、yogurt、eggs保留。四组用例共同证明了算法核心菜品过敏原数组与回避数组是否存在交集。四、算法设计与解题思路4.1 核心逻辑双重成员判定题目的本质是一个两个集合是否相交的判定问题。对每个菜品执行安全 不存在任何 aa 属于 allergens使得 a ∈ mealAllergens用数组 API 表达即对每个菜品遍历回避列表allergens用mealAllergens.includes(a)判断当前过敏原是否出现在菜品过敏原数组中只要有一次命中该菜品即不安全。4.2 选型依据filter some includesfilter天然保留顺序filter按原数组顺序访问每个元素返回的新数组保持相对顺序直接满足same order given的输出要求且filter不会修改原数组具备纯函数特性。some短路的成员判定——只要找到第一个满足条件的元素立即返回true不需要遍历完整个回避列表对空数组恒返回false恰好对应空回避列表全安全与空过敏原菜品全安全两个边界。includes对字符串数组做严格相等的成员检查语义直白可读性最好。4.3 时间复杂度设meals长度为m单个菜品平均过敏原数为k回避列表长度为a。则最坏情况下每个菜品都要完整比对总时间复杂度为O(m × k × a)空间复杂度为O(m)输出数组不含filter内部临时判定。在 365 道每日挑战的题量尺度下这种规模完全可接受如果数据量巨大可先用Set把回避列表转为哈希集合将内层查找降到 O(1)见第六节扩展方向。五、官方参考解法与逐步解读原题文档自带的官方参考解法如下69cfca90e8a0a6d4d6871c53.md 的# --solutions--段function getAllergenFriendlyMeals(meals, allergens) { return meals .filter(([name, mealAllergens]) !allergens.some(a mealAllergens.includes(a))) .map(([name]) name); }逐步解读解构参数.filter(([name, mealAllergens]) ...)利用数组解构直接取出每道菜的菜名name和过敏原数组mealAllergens避免书写meal[0]、meal[1]这类下标访问。判定谓词allergens.some(a mealAllergens.includes(a))检测菜品过敏原是否与回避列表有交集外面套!取反交集为空无任何回避过敏原即为安全。保留顺序filter按原顺序产出安全菜品仍为[name, allergens]元组。映射取名字.map(([name]) name)再次解构只保留菜名得到最终输出。该解法的训练价值在于两处数组解构的使用以及someincludes判定交集、!取反、filter保序这一可复用的过滤管线模式。六、可扩展方向与等价实现以下为围绕本题的自然延伸非仓库内既有代码属于学习拓展建议方向一用Set优化回避列表查找function getAllergenFriendlyMeals(meals, allergens) { const avoid new Set(allergens); return meals .filter(([name, mealAllergens]) !mealAllergens.some(a avoid.has(a))) .map(([name]) name); }将回避列表预先哈希化把内层includesO(a)降为Set.has平均 O(1)整体复杂度降为 O(m × k)。方向二every的等价写法function getAllergenFriendlyMeals(meals, allergens) { return meals .filter(([name, mealAllergens]) mealAllergens.every(a !allergens.includes(a))) .map(([name]) name); }用菜品的每个过敏原都不在回避列表中表达同样语义逻辑等价可作对照理解some与every的互为对偶关系。方向三返回完整菜品而非仅名称只需去掉最后的.map(([name]) name)即可返回[name, allergens]元组适合需要携带过敏原明细做二次处理的场景。七、在真实系统中的验证链路7.1 题目的数据结构验证从 api/src/daily-coding-challenge/schemas/daily-coding-challenge.ts 可以看到每日挑战响应体包含challengeLanguage结构const challengeLanguage Type.Object({ tests: Type.Array( Type.Object({ text: Type.String(), testString: Type.String() }) ), challengeFiles: Type.Array( Type.Object({ contents: Type.String(), fileKey: Type.String() }) ) });即每次挑战的 JavaScript和 Python版本都带有tests测试数组testString就是形如assert.deepEqual(...)的测试代码与challengeFiles种子文件内容验证了原题 hints 以可执行断言形式下发到前端的机制。7.2 通过 API 获取当日挑战并本地验证在本地启动 freeCodeCamp API见仓库根目录 api/package.json后可通过公开端点获取挑战内容# 获取当天的每日挑战 curl http://localhost:3000/daily-coding-challenge/today # 按日期获取格式 YYYY-MM-DD curl http://localhost:3000/daily-coding-challenge/date/2026-08-10 # 获取某月所有挑战的摘要id / challengeNumber / date / title curl http://localhost:3000/daily-coding-challenge/month/2026-08后端行为有几点值得注意见 daily-coding-challenge.ts 与 helpers.ts 源码时区基准/today与/date/:date都基于美国中部时间America/Chicago当天零点判定getNowUsCentral()先计算时区偏移再取 UTC 零点避免跨时区提前看到明天的题未来题目不可见date getUtcMidnight(getNowUsCentral())的请求返回 404闰日映射getSourceDate()中2 月 29 日会映射到2 月 28 日的题目年度循环仓库注释表明2025-08-11至2026-08-10生成了整整一年的挑战getSourceDate会把任意请求日期映射回这一原始区间ORIGINAL_START_MONTH 8、ORIGINAL_START_DAY 11。7.3 本地快速自测将参考解法粘贴进浏览器控制台或 Node REPL直接执行原题四组断言即可验证function getAllergenFriendlyMeals(meals, allergens) { return meals .filter(([name, mealAllergens]) !allergens.some(a mealAllergens.includes(a))) .map(([name]) name); } const assert require(node:assert); // 或浏览器中的断言库 assert.deepEqual(getAllergenFriendlyMeals([[pasta, [wheat, milk]], [salad, [nuts]]], [milk]), [salad]); assert.deepEqual(getAllergenFriendlyMeals([[steak, [soy]], [fried rice, []], [fish tacos, [fish, wheat]], [chicken parmesan, [wheat, milk]]], [soy, fish]), [fried rice, chicken parmesan]); assert.deepEqual(getAllergenFriendlyMeals([[oatmeal, [nuts]], [pancakes, [wheat, milk]], [granola, []], [yogurt, [milk]], [eggs, [eggs, milk]], [toast, [wheat]]], [eggs, milk]), [oatmeal, granola, toast]); assert.deepEqual(getAllergenFriendlyMeals([[oatmeal, [nuts]], [pancakes, [wheat, milk]], [granola, []], [yogurt, [milk]], [eggs, [eggs, milk]], [toast, [wheat]]], [wheat, nuts]), [granola, yogurt, eggs]);四条断言全部通过即代表实现正确。八、小结Challenge 269 Allergen Friendly Meals 是 freeCodeCamp 每日编程挑战中一道典型的数组过滤 集合交集判定题目。通过它你可以系统掌握需求拆解将不含任何指定过敏原翻译为两个字符串数组交集为空的精确判定API 组合filter保序过滤some短路存在性判定includes成员检查 数组解构[name, mealAllergens]边界处理空过敏原菜品、空回避列表、多过敏原交叉命中平台机制挑战 hints 以assert.deepEqual断言形式下发题目经 daily-coding-challenges-javascript.json 管理由 daily-coding-challenge.ts 路由按日对外提供。这道题的解法模式arr.filter(predicate).map(extract)两段式管线在 freeCodeCamp 365 道每日挑战中反复出现是训练数组高阶函数直觉的最佳入门题之一。【免费下载链接】freeCodeCampfreeCodeCamp.orgs open-source codebase and curriculum. Learn math, programming, and computer science for free.项目地址: https://gitcode.com/GitHub_Trending/fr/freeCodeCamp创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表