【问题标题】:Looking for an FP algorithm to compose objects from dot-separated strings寻找一种 FP 算法来从点分隔的字符串中组合对象
【发布时间】:2014-05-16 21:10:23
【问题描述】:

我正在尝试使用函数式编程来解决特定问题。我的猜测是折叠应该可以完成这项工作,但到目前为止,我还没有找到解决方案。

从像 "a.b.c" 这样的点分隔字符串开始,我想构建一个 Javascript 对象,它在 JS 文字符号中看起来像:

obj = {a:{b:{c:"whatever"}}}

算法应该接受一个种子对象开始。在前面的例子中,种子是{}

如果我提供{a:{f:"whatever else"}} 作为种子,结果将是

{a:{f:"whatever else",b:{c:"whatever"}}}

我希望我的描述足够清楚。我不是在谈论字符串操作。我想创建合适的对象。

我正在使用 Javascript,因为这是出现这个现实世界问题的语言,我将在其中实施我希望通过在这里询问找到的 FP 解决方案。

编辑:我要解决的主要问题是如何避免可变对象。 JS 在添加/删除属性方面过于宽松,在这种情况下,我想确保在 FP 例程运行期间不会有副作用。

【问题讨论】:

  • 为什么专注于FP?您是否已经有了没有 FP 的解决方案?请向我们展示您的尝试以及您遇到的问题。
  • 我专注于 FP,因为我想利用不变性。非 FP 解决方案是一个迭代器,它进入种子并对其进行变异。我正在尝试使用正确折叠的解决方案。我的结果与种子 {} 一起工作正常,但在复杂种子的情况下失败。
  • 必须找到我当前的折叠正确解决方案并将其发布在这里。抱歉,今天下午时间太少了:-)
  • 您的意思是对于{a:{f:"whatever else"}} 示例,您想返回一个副本 而不是改变种子?

标签: javascript algorithm functional-programming fold


【解决方案1】:
var seed = {},
    str = "a.b.c";
str.split(".").reduce(function(o, p) {
    return p in o ? o[p] : (o[p] = {});
}, seed);

console.log(seed); // {"a":{"b":{"c":{}}}}

【讨论】:

  • 这个解决方案,抛开突变不谈,向我展示了折叠在操纵除列表之外的累加器方面的力量。在某种程度上,在累加器列表前面添加一个头部和在累加器对象的深处添加一个层次之间没有区别。
  • ...由于自执行功能,您为下一次迭代准备累加器的方式绝对是 BRILLIANT
  • 自执行功能?这里没有 IEFE。
  • 好吧,现在你提到它了。您如何称呼(o[p]={}) 成语?我试图用(function(){ o[p] = {};})() 和类似的方法重现它,但我发现它并不完全相同。你的代码返回 o[p],这让我很困惑。
  • 好的,我知道了。不知道作业会返回东西。我会说他们返回未定义,但这样更有意义。这么多年了,JS 还是让我吃惊……
【解决方案2】:

功能齐全的变体:

function traverse(tree, path, leftover) {
    if (!tree || !path.length)
        return leftover(path);
    var ntree = {};
    for (var p in tree)
        ntree[p] = tree[p];
    ntree[path[0]] = traverse(tree[path[0]], path.slice(1), leftover);
    return ntree;
}
function create(path, value) {
    if (!path.length)
        return value;
    var tree = {};
    tree[path[0]] = create(path.slice(1), value);
    return tree;
}

function set(tree, pathstring, value) {
    return traverse(tree, pathstring.split("."), function(path) {
        return create(path, value);
    });
}

var seed = {a:{f:"whatever else"}};
var obj = set(seed, "a.b.c", "whatever")
    // {"a":{"f":"whatever else","b":{"c":"whatever"}}}
set({}, "a.b.c", "whatever")
    // {"a":{"b":{"c":"whatever"}}}

【讨论】:

  • 好的,很有启发性的例子。 ntree[p] = tree[p] 是一个浅拷贝,但我知道如何处理它。建设ntree[path[0]] = traverse(tree[path[0]],...); return ntree; 是一个珍贵的外卖。我想你发现这一切都很简单,但恕我直言,事实并非如此。谢谢...
猜你喜欢
  • 2021-07-06
  • 1970-01-01
  • 1970-01-01
  • 2013-08-26
  • 2011-11-20
  • 1970-01-01
  • 2017-12-19
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多