JSON在JavaScript中找到

zap*_*ing 59 javascript search json

除了循环以寻找JSON数据之外,还有更好的方法吗?这是编辑和删除.

for(var k in objJsonResp) {
  if (objJsonResp[k].txtId == id) {
    if (action == 'delete') {
      objJsonResp.splice(k,1);
    } else {
      objJsonResp[k] = newVal;
    }
    break;
  }
}
Run Code Online (Sandbox Code Playgroud)

数据被安排为地图列表.喜欢:

[
  {id:value, pId:value, cId:value,...},
  {id:value, pId:value, cId:value,...},
  ...
]
Run Code Online (Sandbox Code Playgroud)

T.J*_*der 186

(您不是在搜索"JSON",而是在搜索数组 - JSON字符串已经被反序列化为对象图,在本例中是一个数组.)

一些选择:

使用对象而不是数组

如果你控制了这个东西的产生,它必须是一个数组吗?因为如果没有,那就有一个更简单的方法.

说这是你的原始数据:

[
    {"id": "one",   "pId": "foo1", "cId": "bar1"},
    {"id": "two",   "pId": "foo2", "cId": "bar2"},
    {"id": "three", "pId": "foo3", "cId": "bar3"}
]
Run Code Online (Sandbox Code Playgroud)

你可以做以下事吗?

{
    "one":   {"pId": "foo1", "cId": "bar1"},
    "two":   {"pId": "foo2", "cId": "bar2"},
    "three": {"pId": "foo3", "cId": "bar3"}
}
Run Code Online (Sandbox Code Playgroud)

然后通过ID查找相关条目是微不足道的:

id = "one"; // Or whatever
var entry = objJsonResp[id];
Run Code Online (Sandbox Code Playgroud)

......正如更新它:

objJsonResp[id] = /* New value */;
Run Code Online (Sandbox Code Playgroud)

...并删除它:

delete objJsonResp[id];
Run Code Online (Sandbox Code Playgroud)

这利用了以下事实:在JavaScript中,您可以使用属性名称作为字符串索引到对象 - 并且该字符串可以是文字,或者它可以来自变量,id如上所述.

放入ID到索引图

(愚蠢的想法,早于上述.保留历史原因.)

看起来你需要将它作为一个数组,在这种情况下除了你想在它上面放置一个地图之外没有比搜索数组更好的方法,如果你能控制它的生成就可以做到这一点.宾语.比如说,你最初有这个:

[
    {"id": "one",   "pId": "foo1", "cId": "bar1"},
    {"id": "two",   "pId": "foo2", "cId": "bar2"},
    {"id": "three", "pId": "foo3", "cId": "bar3"}
]
Run Code Online (Sandbox Code Playgroud)

生成代码可以提供id-to-index映射:

{
    "index": {
        "one": 0, "two": 1, "three": 2
    },
    "data": [
        {"id": "one",   "pId": "foo1", "cId": "bar1"},
        {"id": "two",   "pId": "foo2", "cId": "bar2"},
        {"id": "three", "pId": "foo3", "cId": "bar3"}
    ]
}
Run Code Online (Sandbox Code Playgroud)

然后在变量中获取id的条目id是微不足道的:

var index = objJsonResp.index[id];
var obj = objJsonResp.data[index];
Run Code Online (Sandbox Code Playgroud)

这利用了您可以使用属性名称索引到对象的事实.

当然,如果这样做,则必须在修改阵列时更新映射,这可能会成为维护问题.

但是,如果您无法控制对象的生成,或者更新ids-to-index的映射是太多的代码和/或维护问题,那么您将不得不进行暴力搜索.

蛮力搜索(更正)

有点OT(虽然你确实问过是否有更好的方法:-)),但循环数组的代码是不正确的.这里有详细介绍,但你不能for..in用来遍历数组索引(或者更确切地说,如果你这样做,你必须特别努力); for..in循环遍历对象属性,而不是数组索引.使用非稀疏数组(和你的非稀疏数组)最好的选择是标准的老式循环:

var k;
for (k = 0; k < someArray.length; ++k) { /* ... */ }
Run Code Online (Sandbox Code Playgroud)

要么

var k;
for (k = someArray.length - 1; k >= 0; --k) { /* ... */ }
Run Code Online (Sandbox Code Playgroud)

无论你喜欢什么(后者在所有实现中并不总是更快,这对我来说是违反直觉的,但我们确实如此).(使用稀疏数组,您可以使用for..in但是再次采取特殊的措施来避免陷阱;在上面链接的文章中更多.)

使用for..in阵列上似乎在简单的情况下工作,因为数组为每个它们的索引,而他们唯一的默认属性(属性length和它们的方法)被标记为不可枚举.但是一旦你设置(或框架设置)数组对象上的任何其他属性(它完全有效;数组只是在length属性周围进行一些特殊处理的对象),它就会中断.

  • @TJCrowder - 我原本以为需要一个递归版本而且只做了一个.我建议给定的解决方案只是顶层,看看你的想法是什么.如果其他人对使用递归版本感兴趣我在下面发布它. (3认同)
  • @TJCrowder - 这不适用于真正的对象图.您只覆盖一层(顶部).如果此模型更复杂,则无法找到嵌套值. (2认同)

Tra*_*s J 8

我遇到过这个问题的复杂模型有几个嵌套对象.我正在做的事情的一个很好的例子是:让我们说你有自己的宝丽来.然后将那张照片放入汽车后备箱.汽车在一个大箱子里面.箱子里装着一艘装有许多其他板条箱的大船.我不得不搜索一下,看看板条箱,检查后备箱,然后寻找我现有的照片.

我找不到任何在线使用的好解决方案,并且.filter()只能在阵列上使用.大多数解决方案建议只检查是否model["yourpicture"]存在.这是非常不受欢迎的,因为从这个例子来说,只能搜索船的货舱,我需要一种方法让它们从兔子洞的下方越来越远.

这是我提出的递归解决方案.在评论中,我从TJ Crowder确认需要一个递归版本.我想我会分享它,以防任何人遇到类似的复杂情况.

function ContainsKeyValue( obj, key, value ){
    if( obj[key] === value ) return true;
    for( all in obj )
    {
        if( obj[all] != null && obj[all][key] === value ){
            return true;
        }
        if( typeof obj[all] == "object" && obj[all]!= null ){
            var found = ContainsKeyValue( obj[all], key, value );
            if( found == true ) return true;
        }
    }
    return false;
}
Run Code Online (Sandbox Code Playgroud)

这将从图形内的给定对象开始,然后递归找到的任何对象.我这样使用它:

var liveData = [];
for( var items in viewmodel.Crates )
{
    if( ContainsKeyValue( viewmodel.Crates[items], "PictureId", 6 ) === true )
    {
        liveData.push( viewmodel.Crates[items] );
    }
}
Run Code Online (Sandbox Code Playgroud)

这会产生一个包含我的照片的Crates数组.


Hak*_*gin 6

切换 - 你可以使用这个javascript lib; DefiantJS.无需将JSON数据重组为对象以简化搜索.相反,您可以使用XPath表达式搜索JSON结构,如下所示:

    var data = [
   {
      "id": "one",
      "pId": "foo1",
      "cId": "bar1"
   },
   {
      "id": "two",
      "pId": "foo2",
      "cId": "bar2"
   },
   {
      "id": "three",
      "pId": "foo3",
      "cId": "bar3"
   }
],
res = JSON.search( data, '//*[id="one"]' );

console.log( res[0].cId );
// 'bar1'
Run Code Online (Sandbox Code Playgroud)

DefiantJS使用新方法扩展全局对象JSON; "search"返回带匹配的数组(如果没有找到则返回空数组).您可以通过粘贴JSON数据并在此处测试不同的XPath查询来自行尝试:

http://www.defiantjs.com/#xpath_evaluator

如您所知,XPath是一种标准化的查询语言.