Obtain a roster of given names along with last initial, if needed

Within my JavaScript code, I have an object structured as follows:

[
    {
        firstname: "John",
        lastname: "Smith"
    },
    {
        firstname: "Peter",
        lastname: "Gregory"
    },
    {
        firstname: "John",
        lastname: "Fisher"
    },
    {
        firstname: "Sam",
        lastname: "Fisher"
    }
]

My goal is to present the first names in a comma-separated string. The challenge lies in displaying the first initial of the last name only when necessary to differentiate two individuals with the same first name.

Ultimately, the output should resemble this:

John S., Peter, John F., Sam

Up until now, I've managed to create a loop that retains past initials. However, the obstacle arises with the fourth entry in the given example; an individual whose last name sets them apart from others but does not share a first name with anyone.

What would be the most efficient approach to tackle this issue?

Answer №1

To achieve this task, you can use Array.map along with Array.join. At the bottom of this answer, I have included a polyfill for Array.map in case you require it.

var people = [
{
    firstname: "John",
    lastname: "Smith"
},
{
    firstname: "Peter",
    lastname: "Gregory"
},
{
    firstname: "John",
    lastname: "Fisher"
},
{
    firstname: "Sam",
    lastname: "Fisher"
}
]

/* Count number of firstNames */
var firstnames = {};
for (var i = 0; i < people.length; i++) {
   if (!firstnames[people[i].firstname]) {
       firstnames[people[i].firstname] = 0;
   }
   firstnames[people[i].firstname] ++;
}

/* Create the string of names */
var peopleString = people.map(function (a) {
   /* Check if we need a last name here */ 
   var lastname = firstnames[a.firstname] > 1 ? (a.lastname ? ' ' + a.lastname.substr(0, 1) + '.' : '') : '';
   
   return a.firstname + lastname; 
}).join(', ');

document.write(peopleString);


/*Polyfill for Array.map taken from MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map#Polyfill*/
// Production steps of ECMA-262, Edition 5, 15.4.4.19
// Reference: http://es5.github.io/#x15.4.4.19
if (!Array.prototype.map) {

  Array.prototype.map = function(callback, thisArg) {

    var T, A, k;

    if (this == null) {
      throw new TypeError(' this is null or not defined');
    }

    // 1. Let O be the result of calling ToObject passing the |this| 
    //    value as the argument.
    var O = Object(this);

    // 2. Let lenValue be the result of calling the Get internal 
    //    method of O with the argument "length".
    // 3. Let len be ToUint32(lenValue).
    var len = O.length >>> 0;

    // 4. If IsCallable(callback) is false, throw a TypeError exception.
    // See: http://es5.github.com/#x9.11
    if (typeof callback !== 'function') {
      throw new TypeError(callback + ' is not a function');
    }

    // 5. If thisArg was supplied, let T be thisArg; else let T be undefined.
    if (arguments.length > 1) {
      T = thisArg;
    }

    // 6. Let A be a new array created as if by the expression new Array(len) 
    //    where Array is the standard built-in constructor with that name and 
    //    len is the value of len.
    A = new Array(len);

    // 7. Let k be 0
    k = 0;

    // 8. Repeat, while k < len
    while (k < len) {

      var kValue, mappedValue;

      // a. Let Pk be ToString(k).
      //   This is implicit for LHS operands of the in operator
      // b. Let kPresent be the result of calling the HasProperty internal 
      //    method of O with argument Pk.
      //   This step can be combined with c
      // c. If kPresent is true, then
      if (k in O) {

        // i. Let kValue be the result of calling the Get internal 
        //    method of O with argument Pk.
        kValue = O[k];

        // ii. Let mappedValue be the result of calling the Call internal 
        //     method of callback with T as the this value and argument 
        //     list containing kValue, k, and O.
        mappedValue = callback.call(T, kValue, k, O);

        // iii. Call the DefineOwnProperty internal method of A with arguments
        // Pk, Property Descriptor
        // { Value: mappedValue,
        //   Writable: true,
        //   Enumerable: true,
        //   Configurable: true },
        // and false.

        // In browsers that support Object.defineProperty, use the following:
        // Object.defineProperty(A, k, {
        //   value: mappedValue,
        //   writable: true,
        //   enumerable: true,
        //   configurable: true
        // });

        // For best browser support, use the following:
        A[k] = mappedValue;
      }
      // d. Increase k by 1.
      k++;
    }

    // 9. return A
    return A;
  };
}

Answer №2

Here's a possible solution you could implement:

let dataMap = {};
let newArray = [];
peopleList.forEach(function(person) {
    if (!dataMap.hasOwnProperty(person.firstName)) {
        let index = newArray.push(person.firstName);
        dataMap[person.firstName] = {index: index - 1, value: person};
    } else {
        newArray.push(person.firstName + " " + person.lastName.substr(0, 1));
        newArray[dataMap[person.firstName].index] = dataMap[person.firstName].value.firstName + " " + dataMap[person.firstName].value.lastName.substr(0, 1);
    }
});
console.log(newArray);

Answer №3

If you're looking for a more concise solution, consider this approach:

const people = [
    {
        firstName: "Alice",
        lastName: "Smith"
    },
    {
        firstName: "Bob",
        lastName: "Johnson"
    },
    {
        firstName: "Alice",
        lastName: "Jones"
    },
    {
        firstName: "Tom",
        lastName: "Jones"
    }
];

const result = people.map(person => {
    const count = people.filter(p => p.firstName === person.firstName).length;
    return count > 1 ? `${person.firstName} ${person.lastName.charAt(0)}` : person.firstName;
}).join(", ");

console.log(result);

You can also test it on a fiddle here. Keep in mind that this solution may not be as efficient since we are looping through the entire array multiple times.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

What causes *ngIf to display blank boxes and what is the solution to resolve this problem?

I am currently working on an HTML project where I need to display objects from an array using Angular. My goal is to only show the objects in the array that are not empty. While I have managed to hide the content of empty objects, the boxes holding this co ...

What is the best way to merge append() and replaceWith() functions in jQuery?

Is there a way in Jquery to merge the functions of append() and replaceWith()? In my JQM project, I have a login form that appears on every page. Since multiple pages are loaded into the DOM, I need to shift the form along as the user navigates through th ...

Unable to conceal the innerHTML once the error has been rectified

My error messages are displayed using innerHTML. How can I make them disappear once the error is corrected? Currently, they stay on, even after the error is fixed. I tried resetting them at the top of the script but it didn't work. Link to JSfiddle ...

How to effectively utilize ViewChildren _results in Angular 4?

I'm working with a list of checkboxes that are generated within an ngFor loop: <md-checkbox #hangcheck [id]="hangout?.$key" class="mychecks" > I'm Interested </md-checkbox> To reference these checkb ...

Is there a way to transform a JavaScript array into JSON format in order to use it as the returned data from a RESTful API

Currently, I am exploring how to efficiently convert an array of arrays into a JSON string for retrieval through a RESTful API. On my server, data is fetched from a database in the format: {"user":"some name","age":number ...

Leveraging properties in computed Vue.js

I have a computed property that looks like this: display() { return this.labs.map(function(x, i) { return [x, this.plotDt[i]]; }); } This property receives data as props: props: ["plotDt", "labs"], Both plotDt and labs are ar ...

a series of inputs in coffescript

I'm struggling to gather a variety of inputs and I have no idea how to do this in CoffeeScript. Thank you for any suggestions. Also, when I add another input to the script, the first one stops working. previewBoxWidth = 256 previewBoxHeight = 180 c ...

Here is the key question: What is the best way to identify the most frequently occurring number in an array

A number is considered popular if it shows up at least N/4 times in the array (where N is the total length of the array). Utilizing the sorted nature of the array, he challenged me to devise a more efficient solution than O(n) time complexity. ...

Upload an image to a Node.js API using the Next.js API directory

I am working with a file instance that I obtained from the formidable library. Here's how it looks: photo: File { _events: [Object: null prototype] {}, _eventsCount: 0, _maxListeners: undefined, size: 16648, path: 'public/ ...

Please click the provided link to display the data in the div. Unfortunately, the link disappearance feature is currently not

What I'm Looking For I want the data to be displayed when a user clicks on a link. The link should disappear after it's clicked. Code Attempt <a href="javascript:void(0);" class="viewdetail more" style="color:#8989D3!important;">vi ...

How can I pass the data-attribute ID from JavaScript to PHP on the same index page using ajax?

I am struggling with the title for this section. Please feel free to modify it as needed. Introduction: I have been working on setting up a datatables.net library server-side table using JSON and PHP. Most of the work is done, but I am facing challenges w ...

Ensure that all links are opened in a new tab

When including _blank in the a href URL, my website contains various elements like iframes and ads from Adsense, Taboola,, etc. Currently, when a user clicks on an iframe or ad, it opens in the same window. Is there a way to ensure that all URLs (includin ...

Issues with PHP jQuery AJAX functionality have been observed in Chrome and Internet Explorer, whereas the feature functions properly in Mozilla Firefox

Greetings, my dear friends! I am facing an issue with an AJAX call to update a paragraph tag in HTML. It works perfectly fine in Firefox and Opera, but unfortunately does not work in Chrome and IE. function updatepart() { var count = jQuery('.ab ...

Convert a list into nested JSON items by utilizing the getJSON function

Below is an example of a JSON object: {"sessions":[ { "totalusers":"2", "Users": [ { "id": 1, "name": "abc" }, { "id": 2, "name": "def" } ] } ]} Here is the corresponding HTML structure: <div> ...

Ways to modify the function to restrict its operation to the specific id, class, or selector

I've created a jQuery function that copies checkbox values to the textarea with the ID #msg. $(document).ready(function(){ $("input:checkbox").click(function() { var output = ""; $("input:checked").each(function() { ...

Navigating with ExpressJS

I am looking to enhance the flexibility of routing for handling slashes, such as app.get('/home/pages') The router should be able to manage ////home///pages /home/pages//// etc... requests. I have a potential solution in mind, but it requ ...

The issue with the jQuery function lies in its inability to properly retrieve and return values

Within my code, I have a function that looks like this: $.fn.validate.checkValidationName = function(id) { $.post("PHP/submitButtonName.php", {checkValidation: id}, function(data) { if(data.returnValue === true) { name = true; } else { ...

Implementing a unique shader on a sprite using THREE.js

My goal is to apply procedural structures to faces, starting with the task of creating a billboard featuring a nuclear blast in open space. I attempted to create an animated radial gradient for this, and achieved some success. The key element for each fra ...

Encountered a null value while converting a string to a date, formatting it, and then converting it back to

I have a specific date format: Sun, 07 Feb 2016 21:16:21 +0000 My requirement is to convert it into: dd.MM.yyyy The issue arises when using the following method, resulting in a fatal error with nil if parsedElement == "date" { if currentArticle.date ...

Vue's v-for modifies the initial element within the list

I currently have a vue pinia store called "cartStore": import { defineStore } from 'pinia' export const cartStore = defineStore('cart', { state: ()=>({ cart: [] }), actions:{ async updateQuantity(id,logged,inc){ ...