3

I have the following array:

const people = [
    "JoHn", "ChrISTiana", "anThoNY", "MARia", "jaMeS", "MIChaEl", "jeNNIFeR"
];

I want to capitalise the first letter of each word and lowercase the rest.

I have used the following function to generate a new array:

let capitaliseNames = (arr) => {
  return arr.map((item) => item[0].toUpperCase() + item.slice(1).toLowerCase());
};

But how do I mutate the original array? I have tried the same approach but using forEach and it doesn't seem to work.

Cerbrus
  • 70,800
  • 18
  • 132
  • 147
IoanLT
  • 39
  • 3
  • 2
    Maybe because your `people` is `const`? – Justinas Jun 27 '22 at 09:22
  • 2
    Declare `people` with `let`, then just assign the return value of `capitaliseNames`: `let people = [......]; people = capitaliseNames(people);`. – Cerbrus Jun 27 '22 at 09:22
  • 2
    @holydragon I think you misunderstand the meaning of `const`. – Robby Cornelissen Jun 27 '22 at 09:23
  • You can set the value for each index using `forEach`, e.g. `people.forEach((person, i) => { people[i] = person[0].toUpperCase() + person.slice(1).toLowerCase() });` – bryce Jun 27 '22 at 09:24
  • You shouldn't be mutating the array you're iterating over in a `forEach`, @bryce. – Cerbrus Jun 27 '22 at 09:25
  • 2
    Why is that @Cerbrus? – bryce Jun 27 '22 at 09:26
  • @Cerbrus I'd also be interested in the rationale for that statement. We're not talking about inserting/removing elements here. – Robby Cornelissen Jun 27 '22 at 09:30
  • @Cerbrus `Arrays are Not Constants`. It defines a constant reference to an array. So he can – angel.bonev Jun 27 '22 at 09:31
  • @angel.bonev: Not sure why you tagged me. I'm not claiming the array is immutable. – Cerbrus Jun 27 '22 at 09:33
  • 2
    @bryce As MDN puts it: _"Warning: Concurrent modification of the kind described in the previous paragraph frequently leads to hard-to-understand code and is generally to be avoided (except in special cases)."_ (red block in the [description](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach#description)) It's not a hard rule, more of a convention I always followed. Imo, it does keep code easier to maintain. – Cerbrus Jun 27 '22 at 09:35
  • Does this answer your question? [How to mutate original array in Javascript .map() function?](https://stackoverflow.com/questions/46520833/how-to-mutate-original-array-in-javascript-map-function) – HerrAlvé Jun 27 '22 at 09:42
  • @Cerbrus , sorry my bad. I've misunderstood you. Thanks for the clarification. It's a good convention – angel.bonev Jun 27 '22 at 09:43
  • @Cerbrus *"Concurrent modification of the kind described in the previous paragraph [...]"*. Yet, what we're doing in this case is decidedly not covered in that previous paragraph... – Robby Cornelissen Jun 27 '22 at 09:44
  • @RobbyCornelissen no? _"If existing elements of the array are **changed** or deleted <...>"_ – Cerbrus Jun 27 '22 at 09:45
  • @Cerbrus, yes, continue reading. The paragraph addresses cases where you modify elements before or after the current index. None of which is being done in this case. There are plenty of cases where an array needs to be modified in place, so your stance is that we have to use a `for` loop for that? Agree to disagree. – Robby Cornelissen Jun 27 '22 at 09:46
  • There's nothing to "continue reading" about. That red block talks about _"concurrent modification"_, and _changing_ array entry values is certainly part of that. – Cerbrus Jun 27 '22 at 09:48
  • 1
    @Cerbrus There is **NO** concurrent modification in this case. – Robby Cornelissen Jun 27 '22 at 09:49
  • Hou’re modifying the array you’re ierating over so… – Cerbrus Jun 27 '22 at 10:00
  • if you only need it for display in the web interface, look towards the css property text-transform: capitalize; https://developer.mozilla.org/en-US/docs/Web/CSS/text-transform – Pete Pearl Jun 27 '22 at 10:05
  • @Cerbrus I understand that a discussion can be had in favor of immutable state for a number of use cases. However, there are plenty of scenarios where arrays need to be iterated over and modified in-place, and whether you do that with a `for` loop or a `forEach()` loop makes no material difference. – Robby Cornelissen Jun 27 '22 at 10:07
  • @loadLT why do you need to mutate a constant array ? What's the problem with that array not to be constant ? – angel.bonev Jun 27 '22 at 10:13
  • @RobbyCornelissen I said it’s just a standard I follow, didn’t I? – Cerbrus Jun 27 '22 at 10:20
  • 1
    @angel.bonev This was just my curiosity. I know it's not best practice to mutate the original array, but just wanted to know how to do it. – IoanLT Jun 27 '22 at 10:27

4 Answers4

1

This will do the work

let capitaliseNames = (arr) => { arr.forEach((elem, i) => { arr[i] = elem[0].toUpperCase() + elem.slice(1).toLowerCase() }); };
sathish1409
  • 245
  • 3
  • 6
0

First: toLowerCase() then you can use a custom function for the mutation the first letter.

UPDATE Use a loop where you can manipulate the original array. For example a for loop.

const people = ["JoHn", "ChrISTiana", "anThoNY", "MARia", "jaMeS", "MIChaEl", "jeNNIFeR"];

for(let i = 0; i < people.length; i++) {  
   people[i] = capitalizeFirstLetter( people[i].toLowerCase() ) ;
}

function capitalizeFirstLetter(str) {
  return str[0].toUpperCase() + str.slice(1);
}

console.log(people)
Maik Lowrey
  • 15,957
  • 6
  • 40
  • 79
0

Use forEach() instead of map() and reassign the mutated value back to the original array:

const people = ["JoHn", "ChrISTiana", "anThoNY", "MARia",
                "jaMeS", "MIChaEl", "jeNNIFeR"];

const capitaliseNames = (arr) => arr.forEach(
  (v, i, a) => a[i] = v[0].toUpperCase() + v.slice(1).toLowerCase()
);

capitaliseNames(people);

console.log(people);
Robby Cornelissen
  • 91,784
  • 22
  • 134
  • 156
  • You have my upvode, but personaly I don't think mutating constant arrays is a good practice – angel.bonev Jun 27 '22 at 10:20
  • 1
    @angel.bonev There are plenty of use cases where that is required. Keep in mind that `map()`-ing that array with the same logic requires twice as much memory. Another example is that sometimes change detection strategies in front-end libraries require the array to be mutated in place instead of copied and reassigned. What's more: there are plenty of built-in functions that will mutate arrays in place, `sort()` probably being the most well-known example. – Robby Cornelissen Jun 27 '22 at 10:25
  • just for curiosity why using `a[i] =` and not `arr[i] =` – angel.bonev Jun 27 '22 at 11:06
  • 1
    @angel.bonev It keeps the callback self-contained. No external variables are referenced. – Robby Cornelissen Jun 27 '22 at 11:09
0

Had a go using the for loop and this works:

let capitaliseNames = (arr) => {
    for (let i = 0; i < arr.length; i++) {
        arr[i] = arr[i][0].toUpperCase() + arr[i].slice(1).toLowerCase();
    }
}
IoanLT
  • 39
  • 3