循环通过JSON,在对象之间插入键/值?

时间:2014-12-23 14:33:59

标签: javascript jquery json

更新 - 感谢所有出色的答案和极快的响应。我从建议的解决方案中学到了很多东西。我最终选择了我所做的答案,因为结果与我的要求完全一样,而且我能够以最小的努力在我的应用程序中使用它 - 包括搜索功能。该站点对于开发人员来说是非常宝贵的资源。


可能是一项简单的任务,但我似乎无法在Google上找到任何工作。我是一个Javascript新手和复杂的JSON混淆了我的地狱。我想做的是为我们公司制作一个PhoneGap应用程序(电话簿)。我将尝试解释我的推理并说明我的尝试如下。

我有以下格式的所有员工的JSON数据:

[  
  {  
    "id":"1",
    "firstname":"John",
    "lastname":"Apple",
    "jobtitle":"Engineer"
  },
  {  
    "id":"2",
    "firstname":"Mark",
    "lastname":"Banana",
    "jobtitle":"Artist"
  },
  ... and so on
]

我正在使用的移动框架(框架7)提供了一个"Virtual List"解决方案,我需要利用它,因为我们的目录相当大。虚拟列表要求您知道每个列表项的确切高度,但是,您可以使用函数来设置动态高度。

我要做的是根据姓氏为按字母顺序排列的列表创建“标题”。 JSON数据必须重新构建:

[  
  {
    "title":"A"
  },
  {  
    "id":"1",
    "firstname":"John",
    "lastname":"Apple",
    "jobtitle":"Engineer"
  },
  {
    "title":"B"
  },
  {  
    "id":"2",
    "firstname":"Mark",
    "lastname":"Banana",
    "jobtitle":"Artist"
  },
  ... and so on
]

我已经能够使用for循环向数据中的现有对象添加键/值对:

var letter, newLetter;
for(var i = 0; i < data.length; i++) {
    newLetter = data[i].lastname.charAt(0);
    if(letter != newLetter) {
        letter = newLetter
        data[i].title = letter;
    }
}

此解决方案更改了JSON,从而输出连接到列表项的标题栏(虚拟列表只接受一个<li></li>,因此标题栏是该栏内的div):

{  
  "id":"1",
  "firstname":"John",
  "lastname":"Apple",
  "jobtitle":"Engineer",
  "title":"A"
},
{  
  "id":"1",
  "firstname":"Mike",
  "lastname":"Apricot",
  "jobtitle":"Engineer",
  "title":""
}

这个解决方案有效,直到我尝试在列表中实现搜索功能。当我搜索时,它按预期工作但看起来很糟糕,因为标题标题(“A”,“B”等...)连接到启动特定字母部分的列表项。出于这个原因,我需要能够将标题与现有元素分开,并将它们用于动态高度/从搜索结果中排除。

问题:如何在新字母分组的开头插入[prepends]一个新对象(标题:字母)的for循环?如果有更好的方法,请赐教。正如我所提到的,我是一名JS新手,我希望能够更有效地编写Web应用程序。

3 个答案:

答案 0 :(得分:3)

&#13;
&#13;
var items = [  
  { "lastname":"Apple" },
  { "lastname":"Banana" },
  { "lastname":"Box"  },
  { "lastname":"Bump" },
  { "lastname":"Can" },
  { "lastname":"Switch" }
];
  
var lastC = null;  //holds current title
var updated = [];  //where the updated array will live
for( var i=0;i<items.length;i++) {
  var val = items[i];  //get current item
  var firstLetter = val.lastname.substr(0,1);  //grab first letter
  if (firstLetter!==lastC) {  //if current title does not match first letter than add new title
    updated.push({title:firstLetter});  //push title
    lastC = firstLetter;  //update heading
  }
  updated.push(val);  //push current index
}
console.log(updated);
&#13;
&#13;
&#13;

答案 1 :(得分:1)

现在你有一个对象数组 - 标题前缀为自己的对象可能有点令人困惑 - 更好的结构可能是:

[
  {
    title: "A",
    contacts: [
        {  
            "id":"1",
            "firstname":"John",
            "lastname":"Apple",
            "jobtitle":"Engineer",
            "title":"A"
  }
]

鉴于您当前的结构,您可以循环并推送:

var nameIndexMap = {};
var newContactStructure = [];

for (var i = 0; i < data.length; i++) {
    var letter = data[i].lastname.charAt(0);
    if (nameIndexMap.hasOwnProperty(letter)) {
        //push to existing
        newContactStructure[nameIndexMap[letter]].contacts.push(data[i])
    } else {
        //Create new
        nameIndexMap[letter] = newContactStructure.length;
        newContactStructure.push({
            title: letter,
            contacts: [
                data[i]
            ]
        });
    }
}

newContactStructure现在将包含您的已排序数据。

演示:http://jsfiddle.net/7s50k104/

答案 2 :(得分:0)

使用Array.prototype.splice的简单for循环可以解决问题:

for (var i = 0; i < data.length; i++) {
    if (i == 0 || data[i-1].lastname[0] !== data[i].lastname[0]) {
        data.splice(i, 0, {title: data[i].lastname[0]});
        i++;
    }
}

<强>演示即可。查看下面的演示。

&#13;
&#13;
var data = [  
    {"lastname":"Apple"},
    {"lastname":"Banana"},
    {"lastname":"Bob"},
    {"lastname":"Car"},
    {"lastname":"Christ"},
    {"lastname":"Dart"},
    {"lastname":"Dog"}
];

for (var i = 0; i < data.length; i++) {
    if (i == 0 || data[i-1].lastname[0] !== data[i].lastname[0]) {
        data.splice(i, 0, {title: data[i].lastname[0]});
        i++;
    }
}

alert(JSON.stringify( data, null, 4 ));
&#13;
&#13;
&#13;