2

I have an array with objects, and each object containing a property called name.

Now i want to have a second array containing the first letter of each name property from the first array. This first letter should be saved in a property called header if it doesn't exist yet.

I only want to have a letter to appear once, as this script is intended to be used for a list of alphabetic headers, each containing a list of names starting with the same letter.

I have created a function that uses the build-in JavaScript "filter" method, which is supposed to check if a value with this first letter already exists. But for some reason it doesn't work. The filter always returns an empty array, no matter what letter i provide.

I have been trying to figure out why my script is not working with no success. I greatly appreciate any help with this!

var fruit = [{title:"Apple"},{title:"Avocado"},{title:"Banana"},{title:"Cucumber"}];
var sections = [];
function createAlphabetSections(array) {
        for(var i = 0; i < array.length; i++){
            var firstLetter = array[i].title.charAt(0).toUpperCase();
            var section = sections.filter(function (section) { return section.header === firstLetter;});
            if(sections.length === 0){
                sections.push([{header: firstLetter}]);  
            } else if (section.length > 0){
                sections.push([{header: firstLetter}]);
            }
        }
}
createAlphabetSections(fruit);
kleinermann
  • 55
  • 2
  • 10
  • Please provide an example of expected function output. – halfzebra Nov 05 '15 at 14:42
  • The function should return an array of objects. Each object should have a property called header, which has the first letter of each title property from the first array assigned to it. Duplicates should be removed: `[Object { headerTitle="A"}, Object { headerTitle="B"}, Object { headerTitle="C"}]` – kleinermann Nov 08 '15 at 13:43

2 Answers2

7

First make use map to build a new array from the current array. Then filter out any duplicates.

var sections = fruit.map(function (item) {
    // Return the first letter of the title property
    return item.title.substring(0, 1);
}).filter(function (value, index, self) {
    // http://stackoverflow.com/a/14438954/1789518
    return self.indexOf(value) === index;
});
pmandell
  • 4,288
  • 17
  • 21
  • The code is working great. It took me a while to figure out what is happening here: `return self.indexOf(value) === index;` I understand that self is the array, and indexOf will return the key of the first appearance of a given value. Which means we check here always for the first appearance of a given value in that array. Than we compare if the index of this value is the same as the current index. If it is it means the item is unique and we return true. If the index is different it means we found a duplicate item and return false. The filter method only returns items that return true. – kleinermann Nov 08 '15 at 13:22
  • In my case map() should return an array of objects each containing a property called header. Maybe i'm mistaken, but in this case i think i can not use indexOf() in the filter, because i'm looking to compare two object properties with each other, and not two array values. Is there a way to make the indexOf method work on object properties, or would i have to use a different approach? – kleinermann Nov 08 '15 at 14:28
  • I found a solution that returns me the desired objects. I add another map to the end of the script where i turn all string values into objects: `var sections = fruit.map(function (item) { return item.title.substring(0, 1);}).filter(function (value, index, self) { return self.indexOf(value) === index; }).map(function (item) { return {headerTitle: item} })` – kleinermann Nov 08 '15 at 15:33
1
var getLetters = function(items) {
    var letters = [];

    items.forEach(function(item) {
        if(letters.indexOf(item.title[0].toUpperCase()) === -1) {
            letters.push(item.title[0].toUpperCase());
        }
    });

    return letters;
};

getLetters([{title:"Apple"},{title:"Avocado"},{title:"Banana"},{title:"Cucumber"}]);
Alexander Elgin
  • 6,796
  • 4
  • 40
  • 50