最新消息:Welcome to the puzzle paradise for programmers! Here, a well-designed puzzle awaits you. From code logic puzzles to algorithmic challenges, each level is closely centered on the programmer's expertise and skills. Whether you're a novice programmer or an experienced tech guru, you'll find your own challenges on this site. In the process of solving puzzles, you can not only exercise your thinking skills, but also deepen your understanding and application of programming knowledge. Come to start this puzzle journey full of wisdom and challenges, with many programmers to compete with each other and show your programming wisdom! Translated with DeepL.com (free version)

javascript - Loop Through JSON, Insert KeyValue Between Objects? - Stack Overflow

matteradmin6PV0评论

UPDATE - Thanks for all the great answers and incredibly fast response. I've learned a great deal from the suggested solutions. I ultimately chose the answer I did because the oute was exactly as I asked, and I was able to get it working in my application with minimal effort - including the search function. This site is an invaluable resource for developers.


Probably a simple task, but I can't seem to get this working nor find anything on Google. I am a Javascript novice and plex JSON confuses the hell out of me. What I am trying to do is make a PhoneGap Application (Phone Directory) for our pany. I'll try to explain my reasoning and illustrate my attempts below.

I have JSON data of all of our employees in the following format:

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

The mobile framework (Framework 7) that I am using offers a "Virtual List" solution which I need to take advantage of as our directory is fairly large. The virtual list requires you to know the exact height of each list item, however, you can use a function to set a dynamic height.

What I am trying to do is create "headers" for the alphabetical listing based on their last name. The JSON data would have to be restructured as such:

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

I've been able to add key/value pairs to existing objects in the data using a for loop:

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;
    }
}

This solution changes the JSON, thus outputting a title bar that is connected to the list item (the virtual list only accepts ONE <li></li> so the header bar is a div inside that bar):

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

This solution worked until I tried implementing a search function to the listing. When I search, it works as expected but looks broken as the header titles ("A", "B", etc...) are connected to the list items that start the particular alphabetical section. For this reason, I need to be able to separate the titles from the existing elements and use them for the dynamic height / exclude from search results.

The question: How can I do a for loop that inserts [prepends] a NEW object (title:letter) at the start of a new letter grouping? If there is a better way, please enlighten me. As I mentioned, I am a JS novice and I'd love to bee more efficient programming web applications.

UPDATE - Thanks for all the great answers and incredibly fast response. I've learned a great deal from the suggested solutions. I ultimately chose the answer I did because the oute was exactly as I asked, and I was able to get it working in my application with minimal effort - including the search function. This site is an invaluable resource for developers.


Probably a simple task, but I can't seem to get this working nor find anything on Google. I am a Javascript novice and plex JSON confuses the hell out of me. What I am trying to do is make a PhoneGap Application (Phone Directory) for our pany. I'll try to explain my reasoning and illustrate my attempts below.

I have JSON data of all of our employees in the following format:

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

The mobile framework (Framework 7) that I am using offers a "Virtual List" solution which I need to take advantage of as our directory is fairly large. The virtual list requires you to know the exact height of each list item, however, you can use a function to set a dynamic height.

What I am trying to do is create "headers" for the alphabetical listing based on their last name. The JSON data would have to be restructured as such:

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

I've been able to add key/value pairs to existing objects in the data using a for loop:

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;
    }
}

This solution changes the JSON, thus outputting a title bar that is connected to the list item (the virtual list only accepts ONE <li></li> so the header bar is a div inside that bar):

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

This solution worked until I tried implementing a search function to the listing. When I search, it works as expected but looks broken as the header titles ("A", "B", etc...) are connected to the list items that start the particular alphabetical section. For this reason, I need to be able to separate the titles from the existing elements and use them for the dynamic height / exclude from search results.

The question: How can I do a for loop that inserts [prepends] a NEW object (title:letter) at the start of a new letter grouping? If there is a better way, please enlighten me. As I mentioned, I am a JS novice and I'd love to bee more efficient programming web applications.

Share Improve this question edited Dec 23, 2014 at 15:04 Justin asked Dec 23, 2014 at 14:33 JustinJustin 5685 silver badges20 bronze badges 4
  • 1 Why do you want to use such data structure? Wouldn't it better to have {"A": [...], "B": [...], ...}? – Ginden Commented Dec 23, 2014 at 14:39
  • @Ginden, that sounds to be a good alternative, however I am unsure as to how I would get the dynamic height function working with that structure - see here – Justin Commented Dec 23, 2014 at 14:42
  • @Ginden, my thoughts exactly! I would regroup by title too. – Marventus Commented Dec 23, 2014 at 14:42
  • @Phillips126: assuming you have a set height for each title: {"A": { "height" : "someHeight", "items" : [...] } – Marventus Commented Dec 23, 2014 at 14:43
Add a ment  | 

3 Answers 3

Reset to default 5

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);

Well right now you have an array of objects - prefixing the title as its own object may be a bit confusing - a better structure may be:

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

Given your current structure, you could loop and push:

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 will now contain your sorted data.

Demo: http://jsfiddle/7s50k104/

Simple for loop with Array.prototype.splice will do the trick:

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++;
    }
}

Demo. Check the demo below.

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 ));

Post a comment

comment list (0)

  1. No comments so far