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);
}