Math 用于在列表中查找元组交集的干净代码
我已经编写了一个在命令行工具中查找参数的算法,并希望清理我的代码,但被卡住了 任务 我的程序接收的参数为:Math 用于在列表中查找元组交集的干净代码,math,functional-programming,set,Math,Functional Programming,Set,我已经编写了一个在命令行工具中查找参数的算法,并希望清理我的代码,但被卡住了 任务 我的程序接收的参数为:标志输出输入…|输入标志输出 例如:-d one/path second/path/to/file.txt和second/path/to/file.txt--dir one/path等。每个空格用作分隔符来创建参数数组。参数可以是标志,如-d,也可以是路径 我将每个标志映射到两个数组中,并将其压缩到一个元组数组中。我称之为搜索集 数学符号 我对FP和数学符号都是新手,所以请原谅我的错误(我从
标志输出输入…
|输入标志输出
例如:-d one/path second/path/to/file.txt
和second/path/to/file.txt--dir one/path
等。每个空格用作分隔符来创建参数数组。参数可以是标志,如-d
,也可以是路径
我将每个标志映射到两个数组中,并将其压缩到一个元组数组中。我称之为搜索集
数学符号
我对FP和数学符号都是新手,所以请原谅我的错误(我从维基百科和其他网站学到的)
S用于搜索,而p用于参数
因此,我需要通过在p中搜索Sn+标志后面的下一个参数来查找输出
输入就是Ps∉ P
,所以如果我能得到Ps,这很容易
这使我产生了以下转变:
P -> Pn -> S -> Sn -> Sn = Pn -> Pn + Pₙ+₁
在javascript中,它可以写成:
虽然上面的代码有效,但看起来并不干净。我一直在寻找不同的FP库,比如和不同的python文章,但还没有弄清楚如何使用所有这些聪明的FP函数来清理我的代码
我会接受任何语言的答案,Python、Haskell、Scala等,但请不要使用列表理解。虽然我很有信心可以将您的代码移植到js,但我发现列表理解有点难以移植。最好使用映射
每个
减少
等
如果你也能给我指出正确的方向,我将不胜感激 免责声明
我倾向于远离Javascript。用Javascript做某些事情可能有更好的方法,但我相信一般原则仍然适用
您的代码很好,尽管嵌套有点深
使代码更干净的诀窍是提取抽象功能。在最深的嵌套中,您真正要问的是“元素Pn
是否存在于列表S
中?”这是我可以想象自己在应用程序中多次询问的问题,因此将其转换为函数是完美的。您甚至可以对任何级别的嵌套进行递归:
function ElementInNestedLists(e, l) {
if (l instanceof Array) {
return l.reduce(function(prev, cur, idx, arr) {
if (prev || ElementInNestedLists(e, cur)) {
return true;
}
return false;
}, false);
} else {
return l == e;
}
}
您不必在此处使用reduce
。在函数式编程中,没有什么可以阻止您使用支持它的语言为-循环执行实际的。这可以更好地防止在找到元素后函数继续:
function ElementInNestedLists(e, l) {
if (l instanceof Array) {
for (elem of l) {
if (ElementInNestedLists(e, elem)) {
return true;
}
}
return false;
} else {
return l == e;
}
}
使用此新函数,可以简化tuplesIntersectionParametersPlusNextP
:
function tuplesIntersectionParametersPlusNextP(P, S) {
const Ps = [];
P.forEach( (Pn, n) => {
if (ElementInNestedLists(Pn, S)) {
Ps.push(Pn, P[n + 1]);
}
});
return Ps;
}
但是有一个bug。给定您的输入,此函数的输出为['--dir'、'-d'、'one/path'、\u undefined.
,因为最后一个标志后面没有参数。我们需要添加一个测试来确保至少还有两个元素需要检查
function tuplesIntersectionParametersPlusNextP(P, S) {
const Ps = [];
P.forEach( (Pn, n) => {
if (n + 1 < P.length && ElementInNestedLists(Pn, S)) {
Ps.push(Pn, P[n + 1]);
}
});
return Ps;
}
虽然这是你想要的,但你现在又失去了清洁。解决方案(函数式编程中经常出现的情况)是递归地解决这个问题
function Parse(cmd, flags, acc = []) {
if (cmd.length < 2) {
return acc;
}
if (ElementInNestedLists(cmd[0], flags)) {
acc.push(cmd[0], cmd[1]);
return Parse(cmd.slice(2, cmd.length), flags, acc)
}
return Parse(cmd.slice(1, cmd.length), flags, acc)
}
当然,您可能希望检查并丢弃(或以其他方式处理)标志后面的标志。可能还有其他更复杂的需求,您可能还没有提到或还没有想到,但这些都超出了本答案的范围。nice!我不知道如何递归地做。你的脚步很有教育意义。我想捕获无效标志的原因是,我想抛出描述性错误,为此,我需要知道用户做错了什么。关于您的回答,我可以问您一个问题吗
function tuplesIntersectionParametersPlusNextP(P, S) {
const Ps = [];
P.forEach( (Pn, n) => {
if (ElementInNestedLists(Pn, S)) {
Ps.push(Pn, P[n + 1]);
}
});
return Ps;
}
function tuplesIntersectionParametersPlusNextP(P, S) {
const Ps = [];
P.forEach( (Pn, n) => {
if (n + 1 < P.length && ElementInNestedLists(Pn, S)) {
Ps.push(Pn, P[n + 1]);
}
});
return Ps;
}
function tuplesIntersectionParametersPlusNextP(P, S) {
const Ps = [];
skip = false;
P.forEach( (Pn, n) => {
if (skip) {
skip = false;
return;
}
if (n+1 < P.length && ElementInNestedLists(Pn, S)) {
Ps.push(Pn, P[n + 1]);
skip = true;
}
})
return Ps
}
function Parse(cmd, flags, acc = []) {
if (cmd.length < 2) {
return acc;
}
if (ElementInNestedLists(cmd[0], flags)) {
acc.push(cmd[0], cmd[1]);
return Parse(cmd.slice(2, cmd.length), flags, acc)
}
return Parse(cmd.slice(1, cmd.length), flags, acc)
}
function Parse(cmd, flags, idx = 0, acc = []) {
if (idx + 1 >= cmd.length) {
return acc;
}
if (ElementInNestedLists(cmd[idx], flags)) {
acc.push(cmd[idx], cmd[idx + 1]);
return Parse(cmd, flags, idx + 2, acc);
}
return Parse(cmd, flags, idx + 1, acc);
}