在javascript中的Defaultdict等价物

时间:2013-10-01 23:23:59

标签: javascript jquery

在python中,你可以有一个defaultdict(int),它将int存储为值。如果您尝试对字典中不存在的键执行'get',则默认值为零。

你能在javascript / jquery中做同样的事吗

6 个答案:

答案 0 :(得分:14)

您可以使用JavaScript Proxy

构建一个
var defaultDict = new Proxy({}, {
  get: (target, name) => name in target ? target[name] : 0
})

这使您可以在访问属性时使用与普通对象相同的语法。

defaultDict.a = 1
console.log(defaultDict.a) // 1
console.log(defaultDict.b) // 0

要稍微清理一下,你可以将它包装在构造函数中,或者使用类语法。

class DefaultDict {
  constructor(defaultVal) {
    return new Proxy({}, {
      get: (target, name) => name in target ? target[name] : defaultVal
    })
  }
}

const counts = new DefaultDict(0)
console.log(counts.c) // 0

编辑:上述实现仅适用于基元。它应该通过将构造函数作为默认值来处理对象。这是一个应该与基元和构造函数一起使用的实现。

class DefaultDict {
  constructor(defaultInit) {
    return new Proxy({}, {
      get: (target, name) => name in target ?
        target[name] :
        (target[name] = typeof defaultInit === 'function' ?
          new defaultInit().valueOf() :
          defaultInit)
    })
  }
}


const counts = new DefaultDict(Number)
counts.c++
console.log(counts.c) // 1

const lists = new DefaultDict(Array)
lists.men.push('bob')
lists.women.push('alice')
console.log(lists.men) // ['bob']
console.log(lists.women) // ['alice']
console.log(lists.nonbinary) // []

答案 1 :(得分:9)

结帐pycollections.js

var collections = require('pycollections');

var dd = new collections.DefaultDict(function(){return 0});
console.log(dd.get('missing'));  // 0

dd.setOneNewValue(987, function(currentValue) {
  return currentValue + 1;
});

console.log(dd.items()); // [[987, 1], ['missing', 0]]

答案 2 :(得分:1)

我认为没有相应的东西,但你总是可以写自己的。相当于javascript中的字典将是一个对象,所以你可以这样写它

function defaultDict() {
    this.get = function (key) {
        if (this.hasOwnProperty(key)) {
            return key;
        } else {
            return 0;
        }
    }
}

然后这样称呼它

var myDict = new defaultDict();
myDict[1] = 2;
myDict.get(1);

答案 3 :(得分:0)

添加到安迪·卡尔森的答案中

如果您默认命令dict一个数组,您将在结果对象中获得一个 toJSON 字段。您可以通过解构为新对象来摆脱它。

const dd = new DefaultDict(Array);
//...populate the dict
return {...dd};

答案 4 :(得分:0)

可以使用Proxy

构建快速的肮脏黑客
function dict(factory, origin) {
    return new Proxy({ ...origin }, {
        get(dict, key) {
            // Ensure that "missed" keys are set into
            // The dictionary with default values
            if (!dict.hasOwnProperty(key)) {
                dict[key] = factory()
            }

            return dict[key]
        }
    })
}

所以下面的代码:

n = dict(Number, [[0, 1], [1, 2], [2, 4]])

// Zero is the default value mapped into 3
assert(n[3] == 0)

// The key must be present after calling factory
assert(Object.keys(n).length == 4)

答案 5 :(得分:0)

Proxies 绝对使语法最像 Python,并且有一个名为 defaultdict2 的库,它提供了一个看起来非常清晰和彻底的基于代理的实现,它支持 nested/recursive defaultdicts,某些东西到目前为止,我真的很重视并且在此线程中的其他答案中遗漏了。

也就是说,我倾向于使用像这样的概念验证这样的基于函数的方法让 JS 更“原始”/“原生”:

class DefaultMap {
  constructor(defaultFn) {
    this.defaultFn = defaultFn;
    this.root = new Map();
  }
  
  put(...keys) {
    let map = this.root;
    
    for (const key of keys.slice(0, -1)) {
      map.has(key) || map.set(key, new Map());
      map = map.get(key);
    }

    const key = keys[keys.length-1];
    map.has(key) || map.set(key, this.defaultFn());
    return {
      set: setterFn => map.set(key, setterFn(map.get(key))),
      mutate: mutationFn => mutationFn(map.get(key)),
    };
  }
  
  get(...keys) {
    let map = this.root;

    for (const key of keys) {
      map = map?.get(key);
    }

    return map;
  }
}

// Try it:
const dm = new DefaultMap(() => []);
dm.put("foo").mutate(v => v.push(1, 2, 3));
dm.put("foo").mutate(v => v.push(4, 5));
console.log(dm.get("foo")); // [1, 2, 3, 4, 5]
dm.put("bar", "baz").mutate(v => v.push("a", "b"));
console.log(dm.get("bar", "baz")); // ["a", "b"]
dm.put("bar", "baz").set(v => 42);
console.log(dm.get("bar", "baz")); // 42
dm.put("bar", "baz").set(v => v + 1);
console.log(dm.get("bar", "baz")); // 43

DefaultMap 的构造函数接受一个函数,该函数返回叶节点的默认值。该结构的基本操作是 putget,后者是不言自明的。 put 生成嵌套键链并返回一对函数,这些函数可让您改变或设置这些键末尾的叶节点。访问 .root 为您提供了基础 Map 结构。

如果我忽略了任何错误或错过了有用的功能,请随时发表评论,我会扔掉它。