【问题标题】:How to use array as key in Javascript?如何在 Javascript 中使用数组作为键?
【发布时间】:2012-04-16 12:21:02
【问题描述】:

我有一个关于python的简单例子:

programs = {}
if not programs.has_key(( program, time )):
     programs[( program, time )] = 0
programs[( program, time )] = programs[( program, time )] + 1

如何在Javascript中使用数组作为键?

【问题讨论】:

  • 你的意思是你想使用一个数组作为哈希中的查找?
  • 根据programtime 的可能值,仅使用[program, time] 的字符串表示形式作为键可能不是问题。由于您用作属性的值会自动转换为字符串,因此使用起来很简单。
  • 如Rob所说,像"program_time"这样自定义key,自己处理

标签: javascript


【解决方案1】:

这将“有效”。 (但我不推荐)

var a = {};
var b = [1,2,3];    
a[b] = 'hello';

// a[b] evaluates to 'hello'
// a[[1,2,3]] evaluates to 'hello'
// a['1,2,3'] evaluates to 'hello'

它之所以有效,是因为当您将数组 [1,2,3] 作为散列(映射/关联数组)键传递时,在执行散列查找之前将被转换为字符串 '1,2,3'。只要您不需要两个具有相同值的不同数组映射到不同的哈希值,它就应该满足您的需求。

var c = [1,2,3]
// a[c] evaluates to 'hello' even though we never executed a[c] = 'hello'
// but b == c evaluates to false
// b & c are two separate objects with the same values, so when they
// get converted to a string for hashing, they return the same value from the hash

如前所述,如果您想使用对象引用作为键,您需要的不仅仅是标准的 JavaScript 哈希。

更新

根据@speedplane 的评论:

我怀疑当您将数组传递给哈希键时,JS 会在数组上调用 toString()。因此,您可以轻松测试您实际将获得的密钥:

 ["x", "y", "z"].toString();                // 'x,y,z'
 ["x,y,z"].toString();                    // 'x,y,z'
 [1,2,3].toString();                      // '1,2,3'
 [1,2,'3'].toString();                    // '1,2,3'
 [[1],[2],[3]].toString();                // '1,2,3'
 [["x",1], ["y",2], ["z",3]].toString();  // 'x,1,y,2,z,3'

同样,我建议您不要这样做,除非您真的了解发生了什么。即使那样,我也不会这样做。

【讨论】:

  • 请注意,如果您使用字符串数组作为键,则此方法效果不佳。例如,var a={}; var b = ["x", "y", "z"]; var c = ["x,y,z"]; a[b] = 'uh oh'; a[c] 将评估为 uh oh。两个不同的数组bc 映射到同一个对象键。
  • @speedplane 感谢您指出这一点。我用你的例子更新了我的答案。另外,我明确表示我不建议您这样做。
  • 我对这个答案的受欢迎程度感到惊讶。
  • 您可以通过覆盖 toString 方法来确认 Javascript 确实调用了 toString:let x = [1, 2, 3]; x.toString = ()=>{console.log("Called!")}; let obj = {}; obj[x] = 1;
  • 关于如何验证对 toString 的调用的好主意。从学术兴趣来看,我想知道是否有办法让重新定义的x.toString 仍然返回一个字符串,这样obj[x] 的键不是undefined 而是'1,2,3' .... 我唯一的方法可以弄清楚是创建x的副本:x.toString = ()=>{ let t = [...x]; console.log("Called!"); return t.toString() }
【解决方案2】:

JavaScript 键是字符串。

您需要一个WeakMap 或自定义方法来将数组映射到其他对象。

【讨论】:

  • map.set([1,2], 'woo'); map.get([1,2]) -> 未定义。有没有办法以这种方式使用数组?
  • [1, 2][1, 2] 是不同的对象。使用var arr = [1, 2];map.set(arr, 'woo');map.get(arr, 'woo');。如果您不能保留对数组的引用,那么您必须以某种方式对其进行序列化/散列。天真地,例如使用arr.join(',') 作为键。
  • 是的,我最终以某种奇怪的方式对其进行了散列 :) 我不想使用字符串,因为它可能同时发生数百万次。太糟糕了 - 数组会很好。
【解决方案3】:

我编写了一个名为 array-keyed-map 的库,用于在现代 JavaScript 中稳健地执行此操作。与迄今为止发布的其他答案不同,它不依赖于将值序列化为字符串,而是使用 ES2015 Map 对象,它可以接受任意值作为键。

我将引用my answer to a different question 来获得实现概述,因此该方法会被保留下来,以防库因某种原因消失,或者您想自己实现它:

维护Map 对象的树。每棵树存储:

  • 在内部声明的Symbol 键下:树中该点的值(如果有)。 Symbol 保证唯一性,所以没有 用户提供的值可以覆盖这个键。

  • 在它的所有其他键上:所有其他到目前为止从这棵树设置下一个树。

例如,在akmap.set(['a', 'b'], true) 上,内部树 结构就像——

'a':
  [value]: undefined
  'b':
    [value]: true

在那之后做akmap.set(['a'], 'okay')只会改变 'a' 处路径的值:

'a':
  [value]: 'okay'
  'b':
    [value]: true

要获取数组的值,请在读取时遍历数组 树上的相应键。如果树返回undefined 在任何时候都是不存在的。最后,阅读内部声明 [value] 符号从你到达的树上掉下来。

要删除数组的值,请执行相同操作,但删除所有值 在[value]-symbol-key 下,并删除之后的所有子树 如果它们以 0 的 size 结尾,则递归步骤。


为什么是树?因为当多个数组有 相同的前缀,这在实际使用中非常典型,用于工作 与例如文件路径。

【讨论】:

  • +1 表示树形结构,它融合了“trie”数据结构的精髓,在各种算法中都有用到。 Moreinfo.
【解决方案4】:

这对你有用吗?

jsfiddle

<script>
var ary = {person1:'valerie', person2:'alex'};
for (key in ary) {
    document.write(key, '<br>')
}

document.write(ary['person2'], '<br>')
</script>

【讨论】:

    猜你喜欢
    • 2020-12-09
    • 1970-01-01
    • 2020-03-28
    • 2011-01-01
    • 2015-03-23
    • 2019-11-21
    • 2022-10-18
    • 2014-01-07
    • 2015-05-11
    相关资源
    最近更新 更多