【问题标题】:Find string in array of objects- javascript or jquery在对象数组中查找字符串 - javascript 或 jquery
【发布时间】:2011-08-29 22:35:53
【问题描述】:

我收到了如下所示的 JSON 响应:

{
    "COLUMNS":["SETTING_NAME","SETTING_VALUE","COLOR"],
    "DATA": [
                ["setting_1",100.0,"yellow"],
                ["setting_2",150.0,"red"],
                ["setting_3",30.0,"green"],
                ["setting_4",11.0,"blue"]
            ]
 }

如何找到设置“setting_4”的“颜色”?可接受的解决方案要么是访问数据的简单方法,要么是一种将其转换为爆炸键/值数组的函数,例如

 [
     setting_1_value: '100', 
     setting_1_color: 'yellow', 
     setting_2_value: "150"
     ...
  ]

【问题讨论】:

  • 您想要setting_4 的值是因为您随意选择了那个值,还是因为它是最后一个/最高设置数字?
  • 完全任意。实际数据集要大得多。

标签: javascript jquery arrays object


【解决方案1】:

您可以使用此代码将数据放入您要求的数据结构类型中:

var response = {"COLUMNS":["SETTING_NAME","SETTING_VALUE","COLOR"],
"DATA":[["setting_1",100.0,"yellow"],["setting_2",150.0,"red"],
["setting_3",30.0,"green"],["setting_4",11.0,"blue"]]};

var data = response.DATA;
var columns = response.COLUMNS;
var hash = {}, item, name, i;
var cols = {};

// remember order of columns
for (i = 0; i < columns.length; i++) {
    cols[columns[i]] = i;
}
// fetch data from correct column
for (i = 0; i < data.length; i++) {
    item = data[i];
    name = item[cols["SETTING_NAME"]];
    hash[name + "_value"] = item[cols["SETTING_VALUE"]];
    hash[name + "_color"] = item[cols["COLOR"]];
}
hash.num = data.length;

根据您的要求,这为您提供了这样的数据结构,因此您可以直接读取所需的任何值:

{
    "setting_1_value":100,
    "setting_1_color":"yellow",
    "setting_2_value":150,
    "setting_2_color":"red",
    "setting_3_value":30,
    "setting_3_color":"green",
    "setting_4_value":11,
    "setting_4_color":"blue",
    "num":4
}

这里的 jsFiddle:http://jsfiddle.net/jfriend00/HZmYN/ 生成了这个结果。

个人比较喜欢用这段代码解析成这种类型的数据结构:

var response = {"COLUMNS":["SETTING_NAME","SETTING_VALUE","COLOR"],
"DATA":[["setting_1",100.0,"yellow"],["setting_2",150.0,"red"],
["setting_3",30.0,"green"],["setting_4",11.0,"blue"]]};

var data = response.DATA;
var columns = response.COLUMNS;
var newData = [], item, obj, i, num, match;

var cols = {};

// remember order of columns
for (i = 0; i < columns.length; i++) {
    cols[columns[i]] = i;
}

for (i = 0; i < data.length; i++) {
    item = data[i];
    obj = {};
    obj.value = item[cols["SETTING_VALUE"]];
    obj.color = item[cols["COLOR"]];
    obj.name = item[cols["SETTING_NAME"]];
    match = obj.name.match(/\d+$/);
    if (match && match.length > 0) {
        obj.settingNumber = parseInt(match[0], 10);
    }
    newData.push(obj);
}

// now sort the array by the number in the name setting
newData.sort(function(a, b) {
    return(a.settingNumber- b.settingNumber);
});

并生成这个数据结构:

[
  {"value":100,"color":"yellow","name":"setting_1","settingNumber":1},
  {"value":150,"color":"red","name":"setting_2","settingNumber":2},
  {"value":30,"color":"green","name":"setting_3","settingNumber":3},
  {"value":11,"color":"blue","name":"setting_4","settingNumber":4}
]

在这个 jsFiddle 中说明:http://jsfiddle.net/jfriend00/A23Jd/

我更喜欢这种结构的原因是,您可以更轻松地以对象数组的形式访问“n”设置:

newData[0].color
newData[0].value
newData[0].name
newData[1].color
....

而且,更容易遍历各种设置

【讨论】:

  • 我认为“_value”和“_color”属性后缀应该来自 COLUMNS 数组。硬编码它们不够健壮。
  • 很难知道这里有什么规则以及您可以做出什么假设。不对数据中的内容做出任何假设是不切实际的,因为如果 OP 不假设存在具有这些名称的设置,他们甚至无法查找 setting_4。我们可以添加代码来接受任何列顺序,但您似乎必须知道要查找的列名,所以也许我们可以假设列名。
  • 我喜欢这两个例子有很多原因——主要是因为它们的可读性,尤其是你之后访问对象的方式。谢谢!
  • @jfriend - 可以在数据本身描述目标结构的情况下进行盲数据重组。 OP 可能仍然需要知道在尝试在其他地方使用数据时要查找哪些属性名称,但是重组算法可以(并且可能应该)足够强大以无限扩展。在某些情况下,OP 甚至不需要知道这一点(尽管在面向内部的工具之外我还没有看到太多)。
  • @Tom - 更新了第一段代码以从 COLUMNS 数组中提取列顺序,但由于他要求“知道”每个值是什么的输出数据结构,我假设他知道他正在寻找的列,所以这段代码做出了这个假设。但是,这些列现在可以按任何顺序排列。我现在将更新第二段代码。
【解决方案2】:

使用 $.grep 将允许您访问数据而无需之前映射它们:

var json={"COLUMNS":["SETTING_NAME","SETTING_VALUE","COLOR"],
          "DATA":[["setting_1",100.0,"yellow"],
                  ["setting_2",150.0,"red"],
                  ["setting_3",30.0,"green"],
                  ["setting_4",11.0,"blue"]]}

alert($.grep(json.DATA, function(item){return(item[0]=='setting_4');})[0][2])//returns 'blue'

//or using the labels provided by COLUMNS:

alert($.grep(json.DATA, 
             function(a){return(a[0]=='setting_4');})[0][$.inArray('COLOR',json.COLUMNS)])

【讨论】:

  • 如果您将 Array.prototype.filter 替换为 jQuery.grep 并将 Array.prototype.indexOf 替换为 jQuery.inArray,那么您可能无需依赖 jQuery 就可以做到这一点
  • 这不是对数据的顺序做了很多假设吗?
  • 我最好依赖 jQuery,因为 IE 不支持这两种方法
  • @jfriend00: 当然可以,但是第二个示例使用列中的密钥。我猜 COLUMNS 不是为了好玩,所以 $.inArray('COLOR',json.COLUMNS) 应该总是返回颜色的索引,不管是什么顺序。如果 COLUMNS 没有提供颜色放置位置的信息并且他不能依赖顺序,则没有逻辑方法可以找到颜色或其他任何内容。
【解决方案3】:

你可以用一个简单的 for 循环来做到这一点:

var obj = {"COLUMNS":["SETTING_NAME","SETTING_VALUE","COLOR"],
"DATA":[["setting_1",100.0,"yellow"],["setting_2",150.0,"red"],
["setting_3",30.0,"green"],["setting_4",11.0,"blue"]]};

for(var i = 0; i < obj.DATA.length; i++)
{
    var row = obj.DATA[i]
    if (row[0] == 'setting_4')
    {
        console.log(row[2]);
        break;
    }
}

打印:

blue

【讨论】:

    【解决方案4】:

    您可以简单地减少该数据列表:

    DATA.reduce(function (value, item) { if (item[0] === "setting_4") return item[2] })
    

    您可以将整个内容包装到一个函数中以便于使用,并传入“setting_4”部分。例如

    var getColour = function (id) {
      return DATA.reduce(function (value, item) {
        if (item[0] === id) return item[2]
      })
    }
    

    更新:您可以将两个列表压缩在一起,也许这样可以更轻松地访问?

    obj['DATA'].map(function (row) {
      return obj['COLUMNS'].reduce(function (memo, columnName, index) {
        memo[columnName] = row[index]
        return memo
      }, {})
    })
    

    这将返回如下内容:

    [{
       COLOR: "yellow",
       SETTING_NAME: "setting_1",
       SETTING_VALUE: 100
    }]
    

    【讨论】:

    • 我喜欢像 map 和 reduce 这样的高阶函数,但是你应该指出 array.reduceJavascript 1.8 spec 的一部分,所以对于不支持的浏览器,比如 IE reduce 的实现。
    • 好点。不过它很容易实现,或者你可以使用像 augment.js 这样的库
    • 我认为您希望节省为翻译原始数据结构所做的任何工作的好处,以便将来访问更便宜。这样,我们不必为单个值处理整个数据有效负载并丢弃其余的。我认为使用reduce 排除了任何此类可能性。
    • 哦,太好了,我以前从未听说过那个图书馆,很好的发现。
    【解决方案5】:

    一种将数据集转换为更易于寻址的结构的通用算法。

    var json = {
        "COLUMNS": [
            "SETTING_NAME",
            "SETTING_VALUE",
            "COLOR"],
        "DATA": [
            ["setting_1",100.0,"yellow"],
            ["setting_2",150.0,"red"],
            ["setting_3",30.0,"green"],
            ["setting_4",11.0,"blue"]
        ]
    };
    
    function translateJSON(json) {
        var oHash = {};
    
        var data = json['DATA'];
        var cols = json['COLUMNS'];
    
        for(var i = 0, imax = data.length; i < imax; i++) {
            var row = data[i]; // shorthand
    
            for(var j = 1, jmax = cols.length; j < jmax; j++) {
                var c = cols[j]; // shorthand
                oHash[(row[0] + '_' + c.replace(/[^_]+_/, '')).toLowerCase()] = row[j];
            }
        }
    
        return oHash;
    }
    
    var h = translateJSON(json);
    console.log(h['setting_4_color']);
    

    编辑:更新了代码。 translateJSON 会将 JSON 转换为您描述的数据结构,以便更轻松地访问属性。如果您预计需要从同一个 JSON 有效负载访问多个属性,那么在数据访问之前进行一次性转换比使用 $.grep 之类的东西要高效得多,而且比使用列更简洁 -手动命名交叉引用。

    也就是说,我认为您要求的目标数据结构不一定是最好的。假设您无法更改 JSON 有效负载的结构,最好将其转换为以下内容:

    data = {
        'setting_1': { 'value': 100.0, 'color': 'yellow' },
        'setting_2': { 'value': 150.0, 'color': 'red' }
        ...
    };
    

    【讨论】:

      猜你喜欢
      • 2021-07-25
      • 2022-07-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-12-03
      • 1970-01-01
      相关资源
      最近更新 更多