- Java 双重比较
- java - 比较器与 Apache BeanComparator
- Objective-C 完成 block 导致额外的方法调用?
- database - RESTful URI 是否应该公开数据库主键?
我知道如何使用 cheerio
提取所有( anchor 标记的)href
属性的值。来自使用 request
获得的 responseText
字符串(或 https
)然后创建一个(唯一)URL 的平面对象。
我不明白的是如何使用递归(无需手动编写每个循环)创建(嵌套对象的)嵌套对象。
这个嵌套
对象有一定的深度(使用名为depth
的参数方便地指定)。
例如,假设这是我的代码:
function get(url, callback) {
// get "responseText" using "requests"
// extract the anchor tags href from the "responseText"
callback({"https://url1.com": {}, "https://url2.com": {});
}
get("https://www.example.com", (urls) => {
console.log(urls);
});
当您运行代码时,输出应该是:
{ "https://url1.com": {}, "https://url2.com": {} }
我不明白的是我如何递归地转到 "https://url1.com"
然后得到这个输出:
{ "https://url1.com": { "https://sub-url-1.com": {} }, "https://url2.com": { "https://sub-url-2.com": {} } }
如果深度为5呢?我将如何递归循环每个子 URL 5 层深,然后获取它的子 URL?
这种类型的递归称为什么,我如何在 JavaScript 中实现它?
最佳答案
从 crawl
开始,它需要一个起始 url(字符串)和一个起始深度(int)并返回一个 promise 的结果。我们的结果是我们预期输出的类型(或“形状”)。在这种情况下,它是一个以 url 字符串作为键的对象,值是空对象或另一个嵌套结果 -
// type url = string
// type result = (url, result) object | empty
// crawl : (string * int) -> result promise
const crawl = (initUrl = '/', initDepth = 0) =>
{ const loop = (urls, depth) =>
parallel
( urls
, u =>
depth === 0
? [ u, {} ]
: loop (get (u), depth - 1)
.then (r => [ u, r ])
)
.then (Object.fromEntries)
return loop ([ initUrl ], initDepth)
}
垂直样式并不常见,但有助于眼睛识别与制表位垂直规则对齐的代码元素。开放空白允许注释,但随着对样式的熟悉,它们变得不那么必要了 -
// type url = string
// type result = (url, result) object | empty
// crawl : (string * int) -> result promise
const crawl = (initUrl = '/', initDepth = 0) =>
{ const loop = (urls, depth) =>
parallel // parallel requests
( urls // each url
, u => // as u
depth === 0 // exit condition
? [ u, {} ] // base: [ key, value ]
: loop (get (u), depth - 1) // inductive: smaller problem
.then (r => [ u, r ]) // [ key, value ]
)
.then (Object.fromEntries) // convert [ key, value ]
// to { key: value }
return loop ([ initUrl ], initDepth) // init loop
}
这利用了一个通用实用程序parallel
,它对处理一个 promise 的数组很有用-
// parallel : (('a array) promise * 'a -> 'b) -> ('b array) promise
const parallel = async (p, f) =>
Promise.all ((await p) .map (x => f (x)))
或者如果你不想依赖async-await
-
// parallel : (('a array) promise * 'a -> 'b) -> ('b array) promise
const parallel = (p, f) =>
Promise.all
( Promise
.resolve (p)
.then (r => r .map (x => f (x)))
)
给定一个模拟的 sitemap
和相应的 get
函数 -
// sitemap : (string, string array) object
const sitemap =
{ "/": [ "/a", "/b", "/c" ]
, "/a": [ "/a/1", "/a/11", "/a/111" ]
, "/a/1": [ "/a/1/2", "a/1/22" ]
, "/a/1/2": [ "/a/1/2/3" ]
, "/a/1/2/3": [ "/a/1/2/3/4" ]
, "/a/11": [ "/a/11/2", "a/11/22" ]
, "/a/11/22": [ "/a/11/22/33"]
, "/b": [ "/b/1" ]
, "/b/1": [ "/b/1/2" ]
}
// get : string -> (string array) promise
const get = async (url = '') =>
Promise
.resolve (sitemap[url] || [] )
.then (delay)
// delay : ('a * int) -> 'a promise
const delay = (x, ms = 250) =>
new Promise (r => setTimeout (r, ms, x))
我们可以看到 crawl
如何在不同的深度响应 -
crawl ('/') .then (console.log, console.error)
// { '/': {} }
crawl ('/', 1) .then (console.log, console.error)
// { '/': { '/a': {}, '/b': {}, '/c': {} } }
crawl ('/b', 1) .then (console.log, console.error)
// { '/b': { '/b/1': {} } }
crawl ('/b', 2) .then (console.log, console.error)
// {
// "/b": {
// "/b/1": {
// "/b/1/2": {}
// }
// }
// }
这里我们抓取深度为Infinity
的根"/"
-
crawl ("/", Infinity) .then (console.log, console.error)
// {
// "/": {
// "/a": {
// "/a/1": {
// "/a/1/2": {
// "/a/1/2/3": {
// "/a/1/2/3/4": {}
// }
// },
// "a/1/22": {}
// },
// "/a/11": {
// "/a/11/2": {},
// "a/11/22": {}
// },
// "/a/111": {}
// },
// "/b": {
// "/b/1": {
// "/b/1/2": {}
// }
// },
// "/c": {}
// }
// }
只需将 get
替换为一个接受输入 url 并返回 href 数组的真实函数 - crawl
将以同样的方式工作。
展开下面的代码片段以在您自己的浏览器中验证结果 -
const parallel = async (p, f) =>
Promise.all ((await p) .map (x => f (x)))
const crawl = (initUrl = '/', initDepth = 0) =>
{ const loop = (urls, depth) =>
parallel
( urls
, u =>
depth === 0
? [ u, {} ]
: loop (get (u), depth - 1)
.then (r => [ u, r ])
)
.then (Object.fromEntries)
return loop ([ initUrl ], initDepth)
}
// mock
const sitemap =
{ "/": [ "/a", "/b", "/c" ]
, "/a": [ "/a/1", "/a/11", "/a/111" ]
, "/a/1": [ "/a/1/2", "a/1/22" ]
, "/a/1/2": [ "/a/1/2/3" ]
, "/a/1/2/3": [ "/a/1/2/3/4" ]
, "/a/11": [ "/a/11/2", "a/11/22" ]
, "/a/11/22": [ "/a/11/22/33"]
, "/b": [ "/b/1" ]
, "/b/1": [ "/b/1/2" ]
}
const get = async (url = '') =>
Promise
.resolve (sitemap[url] || [] )
.then (delay)
const delay = (x, ms = 250) =>
new Promise (r => setTimeout (r, ms, x))
// demos
crawl ('/') .then (console.log, console.error)
// { '/': {} }
crawl ('/', 1) .then (console.log, console.error)
// { '/': { '/a': {}, '/b': {}, '/c': {} } }
crawl ('/b', 1) .then (console.log, console.error)
// { '/b': { '/b/1': {} } }
crawl ('/b', 2) .then (console.log, console.error)
// {
// "/b": {
// "/b/1": {
// "/b/1/2": {}
// }
// }
// }
crawl ("/", Infinity) .then (console.log, console.error)
// {
// "/": {
// "/a": {
// "/a/1": {
// "/a/1/2": {
// "/a/1/2/3": {
// "/a/1/2/3/4": {}
// }
// },
// "a/1/22": {}
// },
// "/a/11": {
// "/a/11/2": {},
// "a/11/22": {}
// },
// "/a/111": {}
// },
// "/b": {
// "/b/1": {
// "/b/1/2": {}
// }
// },
// "/c": {}
// }
// }
关于javascript - 这种类型的递归称为什么,我如何在 JavaScript (Node.js) 中实现它?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57419275/
背景: 我最近一直在使用 JPA,我为相当大的关系数据库项目生成持久层的轻松程度给我留下了深刻的印象。 我们公司使用大量非 SQL 数据库,特别是面向列的数据库。我对可能对这些数据库使用 JPA 有一
我已经在我的 maven pom 中添加了这些构建配置,因为我希望将 Apache Solr 依赖项与 Jar 捆绑在一起。否则我得到了 SolarServerException: ClassNotF
interface ITurtle { void Fight(); void EatPizza(); } interface ILeonardo : ITurtle {
我希望可用于 Java 的对象/关系映射 (ORM) 工具之一能够满足这些要求: 使用 JPA 或 native SQL 查询获取大量行并将其作为实体对象返回。 允许在行(实体)中进行迭代,并在对当前
好像没有,因为我有实现From for 的代码, 我可以转换 A到 B与 .into() , 但同样的事情不适用于 Vec .into()一个Vec . 要么我搞砸了阻止实现派生的事情,要么这不应该发
在 C# 中,如果 A 实现 IX 并且 B 继承自 A ,是否必然遵循 B 实现 IX?如果是,是因为 LSP 吗?之间有什么区别吗: 1. Interface IX; Class A : IX;
就目前而言,这个问题不适合我们的问答形式。我们希望答案得到事实、引用资料或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visit the
我正在阅读标准haskell库的(^)的实现代码: (^) :: (Num a, Integral b) => a -> b -> a x0 ^ y0 | y0 a -> b ->a expo x0
我将把国际象棋游戏表示为 C++ 结构。我认为,最好的选择是树结构(因为在每个深度我们都有几个可能的移动)。 这是一个好的方法吗? struct TreeElement{ SomeMoveType
我正在为用户名数据库实现字符串匹配算法。我的方法采用现有的用户名数据库和用户想要的新用户名,然后检查用户名是否已被占用。如果采用该方法,则该方法应该返回带有数据库中未采用的数字的用户名。 例子: “贾
我正在尝试实现 Breadth-first search algorithm , 为了找到两个顶点之间的最短距离。我开发了一个 Queue 对象来保存和检索对象,并且我有一个二维数组来保存两个给定顶点
我目前正在 ika 中开发我的 Python 游戏,它使用 python 2.5 我决定为 AI 使用 A* 寻路。然而,我发现它对我的需要来说太慢了(3-4 个敌人可能会落后于游戏,但我想供应 4-
我正在寻找 Kademlia 的开源实现C/C++ 中的分布式哈希表。它必须是轻量级和跨平台的(win/linux/mac)。 它必须能够将信息发布到 DHT 并检索它。 最佳答案 OpenDHT是
我在一本书中读到这一行:-“当我们要求 C++ 实现运行程序时,它会通过调用此函数来实现。” 而且我想知道“C++ 实现”是什么意思或具体是什么。帮忙!? 最佳答案 “C++ 实现”是指编译器加上链接
我正在尝试使用分支定界的 C++ 实现这个背包问题。此网站上有一个 Java 版本:Implementing branch and bound for knapsack 我试图让我的 C++ 版本打印
在很多情况下,我需要在 C# 中访问合适的哈希算法,从重写 GetHashCode 到对数据执行快速比较/查找。 我发现 FNV 哈希是一种非常简单/好/快速的哈希算法。但是,我从未见过 C# 实现的
目录 LRU缓存替换策略 核心思想 不适用场景 算法基本实现 算法优化
1. 绪论 在前面文章中提到 空间直角坐标系相互转换 ,测绘坐标转换时,一般涉及到的情况是:两个直角坐标系的小角度转换。这个就是我们经常在测绘数据处理中,WGS-84坐标系、54北京坐标系
在软件开发过程中,有时候我们需要定时地检查数据库中的数据,并在发现新增数据时触发一个动作。为了实现这个需求,我们在 .Net 7 下进行一次简单的演示. PeriodicTimer .
二分查找 二分查找算法,说白了就是在有序的数组里面给予一个存在数组里面的值key,然后将其先和数组中间的比较,如果key大于中间值,进行下一次mid后面的比较,直到找到相等的,就可以得到它的位置。
我是一名优秀的程序员,十分优秀!