How to extract and manipulate items in an array Javascript - javascript

I am pretty new to Javascript and I am struggling with one of my assignments.
This is the context:
Manipulate this data
var grades = "jim|25, sue|32, mary|34, ann|22, ted|28, frank|15, lisa|19, mike|30, ahn|26, vishaya|27";
Create an HTML page with inline JavaScript code that displays student data in a more readable format like so:
Name1 - score1
Name2 - score2
Your program should:
display each student name and score
capitalize the first letter of student name
display the total # of students,
display the lowest, highest, and average scores
Now, I was able to print the names and grades in a more readable format but I don't know how to go about capitalizing the first letter of each name and how to output the lowest, highest and average grades.
Here is my code:
<body>
<p id="demo"></p>
<script>
var grades =
"jim|25, sue|32, mary|34, ann|22, ted|28, frank|15, lisa|19, mike|30, ahn|26, vishaya|27";
let result = grades.split(", ");
function getNameAndGrade(Str) {
for (let i in result) {
document.write(
` <b>Name: </b>${result[i].slice(
0,
result[i].indexOf("|")
)} <b>Grade: </b>${result[i].slice(-2)} <br>`
);
}
}
getNameAndGrade(grades);
</script>
</body>

Here's one way you could capitalize the first letter of each name and output the lowest, highest, and average grades:
<body>
<p id="demo"></p>
<script>
var grades = "jim|25, sue|32, mary|34, ann|22, ted|28, frank|15, lisa|19, mike|30, ahn|26, vishaya|27";
let result = grades.split(", ");
let scores = [];
let names = [];
for (let i in result) {
let name = result[i].slice(0, result[i].indexOf("|"));
names.push(name.charAt(0).toUpperCase() + name.slice(1));
scores.push(parseInt(result[i].slice(-2)));
}
// Capitalize first letter of name
for (let i in names) {
document.write(`<b>Name: </b>${names[i]} `);
}
// Display the lowest, highest, and average scores
let lowest = Math.min(...scores);
let highest = Math.max(...scores);
let average = (scores.reduce((a, b) => a + b, 0)) / scores.length;
document.write(`<br><b>Lowest: </b>${lowest}`);
document.write(`<br><b>Highest: </b>${highest}`);
document.write(`<br><b>Average: </b>${average}`);
document.write(`<br><b>Total: </b>${scores.length}`);
</script>
</body>
In this updated code, I first used two arrays to store the names and scores separately. Then I used a for loop to iterate through the names array and capitalize the first letter of each name using the charAt(0).toUpperCase() method, and I used the Array.prototype.push() method to add the capitalized names to the names array.
And I used another for loop to iterate through the scores array and used the Math.min() and Math.max() method to find the lowest and highest scores, and then I used scores.reduce() method to find the average score. And I also used the scores.length to find the total number of students.

You need some refactoring.
First of all, don't let your function write directly to the DOM. Instead, make it return your desired data and prefer modular structure (functions are small and do only one tiny specific task)
function getNameAndGrade(couple) {
return {
name: couple.split('|')[0],
score: couple.split('|')[1]
}
}
To capitalize the first letter, get it with substring method (0 is the position of the substring and 1 is a substring length) and then capitalize it with capitalize. After that, add the rest of your string with substring(1) (1 means here without 1 first letter).
function capitalizeFirstLetter(string) {
string.substring(0, 1).toUpperCase() + string.substring(1)
}
It is a good practise to separate your logic and view. This means, one function for calculations and another one for writing it to the screen. It helps you reuse your code.
function displayCouples(couples) {
const displayData = couples.map(couple =>
`<b>${capitalizeFirstLetter(couple.name)}</b>: ${couple.score}`
)
document.getElementById('demo').innerHTML = displayData
}
To get min, max and average score, we use method map. The only thing it is doing is putting the score instead of the whole name and score object into our math functions. It tells javascript to take the score field and not the whole object.
function getAverageScore(couples) {
return Math.sum(...pairs.map(couple => couple.score)) / couples.length
}
function getMaxScore(couples) {
return Math.max(...couples.map(couple => couple.score))
}
function getMinScore(couples) {
return Math.min(...couples.map(couple => couple.score))
}
And here all the work:
const input = "jim|25, sue|32, mary|34, ann|22, ted|28, frank|15, lisa|19, mike|30, ahn|26, vishaya|27"
// we use hetNameAndGrade inside map function. It means, we apply this function to every pair of name and score
const pairs = input.split(', ').map(getNameAndGrade)
displayCouples(pairs)
const min = getMaxScore(pairs)
const max = getMaxScore(pairs)
const average = getAverageScore(pairs)

For capitalizing words, you can use a mixture of three functions: charAt(), toUpperCase() and slice().
The charAt() function returns the character at a given position in a string.
Example:
const str = 'javascript';
const str2 = str.charAt(0);
console.log(str2);
//Output: j
The toUpperCase() function converts all the characters of an input string to uppercase.
Example:
const str = 'javascript';
const str2 = str.toUpperCase();
console.log(str2);
//Output: JAVASCRIPT
Now, everything is capitalized. We, however need only the first letters to be capitalized. To capitalize the first character of a string, we can use the charAt() to separate the first character and then use the toUpperCase() function to capitalize it. Now, we would get the remaining characters of the string using the slice() function.
The slice() function slices a given string from a specified “start” position until the specified “end” position.
Example:
const str = 'javascript';
const str2 = str.slice(1);
console.log(str2);
//Output: avascript
So, we'll use all three of those to capitalize the first letters.
const str = 'javascript';
const str2 = str.charAt(0).toUpperCase() + str.slice(1);
console.log(str2);
//Output: Javascript

Related

Swapping first letters in name and altering capitalization using JavaScript? (looking to optimize solution)

I was taking on a JS challenge to take a first/last name string input and do the following:
swap the first letter of first/last name
convert all characters to lowercase, except for the first characters, which need to be uppercase
Example:
input: DonAlD tRuMp
output: Tonald Drump
The following is the code I came up with:
const input = prompt("Enter a name:")
function switchFirstLetters(input) {
let stringArray = input.split('');
for(let i=0; i < stringArray.length; i++) {
if(stringArray[i - 1] === ' ') {
[stringArray[0], stringArray[i]] = [stringArray[i], stringArray[0]]; // destructuring
}
}
return result = stringArray.join('');
}
let swappedString = switchFirstLetters(input);
function capFirstLetters(swappedString) {
let stringArray = swappedString.toLowerCase();
stringArray = stringArray.split('');
stringArray[0] = stringArray[0].toUpperCase();
for(let i=0; i < stringArray.length; i++) {
if(stringArray[i - 1] === ' ') {
stringArray[i] = stringArray[i].toUpperCase();
}
}
return result = stringArray.join('');
}
let finalString = capFirstLetters(swappedString);
console.log(finalString);
My thought process for the switchFirstLetters function was:
Create an array from the string parameter
Run through the array length. If the value of the element prior the current element is equal to ' ', use destructuring to swap the current element with the element at index 0
Concatenate elements into a new string and return that value
My thought process for the capFirstLetters function:
Convert all characters in the string to lowercase (this could be handled outside of the function as well)
Create an array from the new, lowercase string
Make character at index 0 be uppercase (this could also be integrated into the for loop)
Run through the array length. If the value of the element prior to the current element is equal to ' ', convert that element to uppercase.
Concatenate array elements into a new string
The code works, but I'm still early in my coding journey and realize it's likely not an ideal solution, so I was wondering if anyone here could help me optimize this further to help me learn. Thanks!
You could also use a regular expression to replace the first letters:
let name = "DonAlD tRuMp";
let result = name.toLowerCase().replace(/(\S)(\S*\s+)(\S)/g, (_, a, b, c) =>
c.toUpperCase() + b + a.toUpperCase()
);
console.log(result);
The regular expression uses \S (a non-white-space character), \S* (zero or more of those), \s+ (one or more white-space characters) and parentheses to create capture groups. These three groups map to a,b,c parameters in the callback function that is passed to replace as second argument. With these parts the replacement string can be constructed. Both the capitalisation and the switch happen in the construction.
If the replace function is a little overwhelming, my attempt introduces the for-of loop, the substring string method, array slice as well as the && short circuit evaluation. You should also be aware you can access a given character of a string using the square bracket syntax, just like array, but string has it's own set of methods which tend to have different names.
Definitely take a look at the replace function, to make your v2.
const rawNameInput = "DonAlD jUnior tRuMp"
const nameInput = rawNameInput.trim()
const rawNameWords = nameInput.split(" ")
const nameWords = []
for (const word of rawNameWords) {
const first = word[0].toUpperCase()
const rest = word.substring(1).toLowerCase()
nameWords.push(first + rest)
}
const middleNames = nameWords.slice(1, -1).join(" ")
const lastIdx = nameWords.length - 1
const newFirstName = nameWords[lastIdx][0] + nameWords[0].substring(1)
const newLastName = nameWords[0][0] + nameWords[lastIdx].substring(1)
console.log(`${newFirstName} ${middleNames && middleNames + " "}${newLastName}`)

generate two variables while using split

I have a string like this
test/something/else
I would like to generate two variables
first = test
second = something/else
I tried with
const [first, ...second] = "test/something/else".split("/");
and it gives me the right value for first but for second it's an array. So I have to join the array to get the value I need?
Use a regular expression to match a (single) / followed by anything, so that the result is the 2 strings you want:
const str = 'test/something/else';
const [, first, second] = str.match(/([^/]+)\/(.*)/);
console.log(first);
console.log(second);
If you had to use split, and you don't want the extra array, you can do something similar by putting the second part into a capture group:
const str = 'test/something/else';
const [first, second] = str.split(/\/(.*)/);
console.log(first);
console.log(second);
Correct, the idiomatic built-in command to do this is to .split() and then .join(‘’) the tail elements.
It may be (very slightly) faster to check for the index and slice the string with that, something like
function splitAt(str, delimiter) {
const idx = str.indexOf(delimiter);
const head = str.slice(0, idx);
const tail = str.slice(idx);
return [head, tail];
}
Solution is simple, we should take 2 variables, in one variable assign the string which includes '/' then in another variable assign split method split(//(.*)/) with expresion and console log it
var str = "how r u?/kkk/jj";
const [first, second] = str.split(/\/(.*)/);
console.log(first);
console.log(second);
split method break the string and assign em to arrays. The string will be break after '/' and whenever console log the item, the broken string will be displayed.

Replace words in var string by elements of array in JS

My code automatically search the string for color names and adds random number suffixes and stores them as elements in an array.
What I want is to create a new string with the new modified elements of my array.
Problem comes when string has multiple occurrences of the same color name.
What I need is to replace these occurrences with the different elements of my exported array one by one.
(I don't want to split string in Array, replace the same elements with the other array in a brand new one and then join it to a string. I need to modify the original string)
Example:
String changes through user input so if i have:
str = ' little red fox is blue and red cat is blue';
then my code finds all color names and produces a new array like that:
array = [ 'red2354' , 'blue7856' , 'red324', 'blue23467'] ;
(my code adds RANDOM suffixes at the end of every color element but the order of my array is the same as the string's occurrences)
Desired Output:
str = ' little red2354 fox is blue7856 and red324 cat is blue23467 ';
I tried so far:
var str = ' little red fox is blue and red cat is blue ';
//I have split string to Array:
ar1 = [ "little","red","fox","is","blue","and","red","cat","is","blue"];
//var dup = matchmine(ar1) find all color duplicates :
var dup = ["red","blue","red","blue"];
//I've sorted all duplicates to appear only once for option B:
var dup2 = ["red","blue"];
//var res = modify(str) takes all color names and adds random suffixes:
var res= ["redA" , "blueA" , "redB", "blueB" ] ;
//I have also create a new array with all strings in case I needed to match lengths:
var final = [ "little","redA","fox","is","blueA","and","redB","cat","is","blueB"];
var i = ar1.length-1;
for ( i ; i >= 0; i--) {
var finalAr = str.replace(ar1[i],final[i]);
str = finalAr;}
alert(finalAr);
Problem is that loop goes and 1st time replace one by one all elements. So far so good but in the following loops replace the first again.
loops result:
str = 'little redAB fox is blueAB and red cat is blue '
Desired output:
str = 'little redA fox is blueA and redB cat is blueB '
Some of your logic remains hidden in your question, like on what grounds you determine which word should get a suffix, or how that suffix is determined.
So my answer cannot be complete. I will assume all words that are duplicate (including "is"). If you already know how to isolate the words that should be taken into consideration, you can just inject your word-selection-logic where I have looked for duplicates.
For the suffix determination, I provide a very simple function which produces a unique number at each call (sequentially). Again, if you have a more appropriate logic to produce those suffixes, you can inject your code there.
I suggest that you create a regular expression from the words that you have identified, and then call replace on the string with that regular expression and use the callback argument to add the dynamic suffix.
Code:
function markDupes(str, getUniqueNum) {
// 1. Get all words that are duplicate (replace with your own logic)
let dupes = str.match(/\S+/g).reduce(({words, dupes}, word) => ({
dupes: words.has(word) ? dupes.concat(word) : dupes,
words: words.add(word)
}), {words: new Set, dupes: []} ).dupes;
// Turn those words into a regular expression. Escape special characters:
dupes = dupes.map(word => word.replace(/[\/\\^$*+?.()|[\]{}]/g, '\\$&'))
.join("|");
let regex = new RegExp(dupes, "g");
// Make the replacement of duplicate words and call the callback function:
return str.replace(regex, word => word + getUniqueNum());
}
// Example has two inputs:
// 1. A function that determines the suffix:
// Every call should return a different value
var getUniqueNum = ((i = 1) => {
// ... here we choose to just return an incremental number
// You may implement some other (random?) logic here
return () => i++;
})();
// 2. The input string
let str = 'little red fox is blue and red cat is blue ';
// The call:
console.log(markDupes(str, getUniqueNum));
Make an object that works as a map for your replacers:
const replacers = {
red: 'redA',
blue: 'blueB'
}
Then split your string into an array of words and map over it, replacing as you go:
const inputStr = 'this is my red string blue words'
const stringArr = inputStr.split(' ')
const result = stringArr.map(word=> replacers[word]?replacers[word]:word). join(' ')

Storing The Sliced Character from .slice Method

When I utilise the slice method like so:
"Hello".slice(0,-1);
The result I get will be "Hell". Then if I run through that again using the same code, I will get "Hel".
Is there a way that I can extract and store into a variable the actual character that was sliced off, in this case "H" or on the second run "e", and not just the remainder of the string?
You could just use a second .slice() on the original string.
For example, where "Hello".slice(0,-1); returns all but the last character, "Hello".slice(-1) returns only the last character.
var input = "Hello";
var removed = input.slice(-1); // "o"
var remaining = input.slice(0, -1); // "Hell"
I don't think there's a more generic solution than that, because .slice() also lets you extract the middle of a string, in which case you'd need two extra calls to get the two parts being removed.
Demo:
var input = "Hello";
var allRemoved = [];
var removed;
while (input != "") {
allRemoved.push(removed = input.slice(-1));
input = input.slice(0, -1);
console.log("'" + removed + "' removed, leaving '" + input + "'");
}
console.log("Removed: " + allRemoved.join(", "));
Alternatively, if you only care about removing characters one at a time, you could forget about .slice() and instead convert the string to an array and use .shift() or .pop() to remove the character at the beginning or end respectively:
var input = "Hello";
var inArr = input.split("");
while (inArr.length > 0) {
console.log(inArr.pop());
}
This might not be the most efficient way to do this but you can turn yout string as an array with .split, then use .splice to remove certain elements ( letters ) and store them as a variable. Finally you turn your variable of removed letters back to a string using .join
let name = 'David'
let arrayname = name.split('')
let chosenLetters = arrayname.splice(0,2)
let finalLetters = chosenLetters.join('')
console.log(finalLetters) //should output Da
For split and join I recommend you leave the argument as (''). For .splice you can find in the docs for js how to select specific letters. In my example I am saying "Start at index 0 and cut the first 2 elements". Splice has many other ways to select an index so I recommend you read the docs.
In one line of code it can be generalized to :
let name = 'David'
let finalLetters = name.split('').splice(0,2).join('')
console.log(finalLetters) //should output Da

JavaScript reverse the order of letters for each word in a string

I am trying to get around the following but no success:
var string = 'erehT era a tsav rebmun fo secruoser rof gninrael erom tpircsavaJ';
var x = string.split(' ');
for (i = 0; i <= x.length; i++) {
var element = x[i];
}
element now represents each word inside the array. I now need to reverse not the order of the words but the order of each letter for each word.
var string = "erehT era a tsav rebmun fo secruoser rof gninrael erom tpircsavaJ";
// you can split, reverse, join " " first and then "" too
string.split("").reverse().join("").split(" ").reverse().join(" ")
Output: "There are a vast number of resources for learning more Javascript"
You can do it like this using Array.prototype.map and Array.prototype.reverse.
var result = string.split(' ').map(function (item) {
return item.split('').reverse().join('');
}).join(' ');
what's the map function doing there?
It traverses the array created by splitting the initial string and calls the function (item) we provided as argument for each elements. It then takes the return value of that function and push it in a new array. Finally it returns that new array, which in our example, contains the reversed words in order.
You can do the following:
let stringToReverse = "tpircsavaJ";
stringToReverse.split("").reverse().join("").split(" ").reverse().join(" ")
//let keyword allows you declare variables in the new ECMAScript(JavaScript)
You can do the following.
var string = "erehT era a tsav rebmun fo secruoser rof gninrael erom tpircsavaJ";
arrayX=string.split(" ");
arrayX.sort().reverse();
var arrayXX='';
arrayX.forEach(function(item){
items=item.split('').sort().reverse();
arrayXX=arrayXX+items.join('');
});
document.getElementById('demo').innerHTML=arrayXX;
JavaScript split with regular expression:
Note: ([\s,.]) The capturing group matches whitespace, commas, and periods.
const string = "oT eb ro ton ot eb, taht si a noitseuq.";
function reverseHelper(str) {
return str.split(/([\s,.])/).
map((item) => {
return item.split``.reverse().join``;
}).join``;
}
console.log(reverseHelper(string));

Categories