Have an array of quotes (quotes), need to find the average length of one particular person's quotes (name).
I can find the values, but do not know how to get the sum of the returned values
let averageQuoteLength = (name) => {
i = crewMembers.indexOf(name)
a=(-1);
while (a <= quotes[i].length) {
a++
console.log(quotes[i][a].length)
}
}
assumes you have a 2 dimensional array more or less like:
var quotes = [
['quote1', 'quote2', 'quote3'],
['quote1', 'quote2', 'quote3'],
['quote1', 'quote2', 'quote3']
]
and some crewMembers array that has all names at the corresponding indices
try this out:
let averageQuoteLength = (name) => {
let i = crewMembers.indexOf(name);
return (quotes[i].reduce((acc, val) => acc += val.length, 0) / quotes[i].length);
};
the array reduce method sums all the length of all quotes in the array at quotes[i], and then I divide by the length of the array to get the average quote length. Reduce is a useful tool worth learning.
Related
I've done something similar in the past with a nested loop, but for some reason I can't get my mind around this to get it to work. I keep running into problems that involve indexing of two separate arrays and it's been a continual stumbling block
In this case, I'm trying to sort a string. The string includes letters and numbers, the task is to sort the letters in reverse alphabetical order while keeping the numbers at their same index.
I've come up with this solution (probably not the most efficient), but can't get the sortString array to come together so that I can join the letters and numbers back into a string.
function reverse(str) {
// split the str into an array
const arr = [...str]
// converts each element in arr to a number, letters are string 'NaN'
const numArray = arr.map(x=> Number(x)).map(x=> x >= 0 ? x : String(x))
// array of the sorted letters
const letters = arr.filter(x=> !/[0-9]/g.test(x)).reverse()
// initiate empty array to hold the combined numbers and letters
let sortString = []
// Use for loop to cycle through and replace elements that are 'NaN' with letters from the letter array. All pushed to sortString.
for (let i=0; i<arr.length; i++) {
sortString.push(numArray[i] === 'NaN' ? letters[0] : numArray[i])
}
return sortString
}
reverse("ab89c") // output should be "cb89a"
You could get an array of non digits, sort it and map the splitted string with the sorted letters in places if not a digit.
const
reverse = string => {
const
array = Array.from(string),
letters = array
.filter(v => /\D/.test(v))
.sort();
return array
.map(v => /\D/.test(v) ? letters.pop() : v)
.join('');
};
console.log(reverse("ab89c"));
A slightly different approach takes a Proxy for the wanted items of sorting:
How to sort only part of array? between given indexes
Here's code that works:
Explanation of how the code works is in-line as comments.
Basically it takes the numbers out, sorts the letters in reverse, and puts the sorted letters back in the right place.
Because it's step-by-step, you could add console log on each variable after it's assigned to see how it works step by step.
function reverse(input) {
// This function from: https://stackoverflow.com/a/32567789/569302
function testIsLetter(c) {
return c.toLowerCase() != c.toUpperCase();
}
// Convert from array to string to process character by character
let inputAsArray = input.split('');
// This is where we'll lookup where to put the letters when we're done
let mapped = inputAsArray.map((s) => {
return {
s,
isLetter: testIsLetter(s)
}
})
// Now that we've captured where the letters are, take the numbers (non-letters) out
let filtered = mapped.filter(m => m.isLetter)
// Convert the object into just letters so they're easily compared when we sort
let filteredAsLettersArray = filtered.map(f => f.s)
// Sort ascending
filteredAsLettersArray.sort()
// Reverse to sort descending
filteredAsLettersArray.reverse()
// Now we need to put the letters back.
let resultAsArray = [];
let letterIndex = 0;
mapped.forEach(m => {
// If it's a letter, we use the sorted result (incrementing letterIndex each time)
if (m.isLetter) {
resultAsArray.push(filteredAsLettersArray[letterIndex]);
letterIndex++;
} else {
// Otherwise we use the number
resultAsArray.push(m.s);
}
});
let result = resultAsArray.join('');
return result;
}
console.log(reverse("ab89c"));
console.log(reverse("1a2eb8f9c"));
I have an array of strings that are numbers.
I am attempting to get back the largest 4 numbers in my array.
const data = [
"1,203,291",
"2,301,291",
"643,092",
"1,391,290",
"32,309",
"3,391"
]
I am attempting to return 2,301,291, 1,391,290, 1,203,291, 643,092
I first start off by removing the commas in a string and converting it into a number.
let topArr = data.map(e => Number(e.replace(/(,\s*)+/g, '').trim()));
Then create another variable which equals the max set of numbers.
let topValues = Math.max(...topArr)
//bring back the commas that were removed to append values with commas
String(topValues).replace(/(.)(?=(\d{3})+$)/g, '$1,')
I've used Math.Max but that only returns the largest number which is 2,301,291 is there a way to alter Math.Max in order to receive the top 4?
Here is my code in full code:
const data = [
"1,203,291",
"2,301,291",
"643,092",
"1,391,290",
"32,309",
"3,391"
]
let topArr = data.map(e => Number(e.replace(/(,\s*)+/g, '').trim()));
let topValues = Math.max(...topArr)
//bring back the commas that were removed to append values with commas
String(topValues).replace(/(.)(?=(\d{3})+$)/g, '$1,')
const data = [
"1,203,291",
"2,301,291",
"643,092",
"1,391,290",
"32,309",
"3,391"
];
let result = data.map(el => Number(el.split(",")
.join("")))
.sort((a,b) => b - a)
.splice(0, 4)
console.log(result);
sort them in descending order then use slice to get first 4
and then again use map and inside callback use the code to add thousand separator
const data = [
"1,203,291",
"2,301,291",
"643,092",
"1,391,290",
"32,309",
"3,391"
]
let topArr = data.map(e => Number(e.replace(/(,\s*)+/g, '').trim()))
// order in descending order
.sort((a, b) => {
return b - a;
})
// get the first 4
.slice(0, 4)
// return a new array & inside callback to add comma separator
.map((item) => {
return String(item).replace(/(.)(?=(\d{3})+$)/g, '$1,')
});
console.log(topArr)
Why not sort them after conversion to numbers and retrieve the last four numbers?
Here is the prompt: Write a function that will return the count of distinct case-insensitive alphabetic characters and numeric digits that occur more than once in the input string. The input string can be assumed to contain only alphabets (both uppercase and lowercase) and numeric digits.
Get all non-unique values (i.e.: duplicate/more than one occurrence) in an array
Get all unique values in a JavaScript array (remove duplicates)
I used variances of the above questions/answers and tried to amend it for what I am looking for- the count of how many elements are found more than once
var arr = 'Indivisibilities';
var sorted_arr = arr.toLowerCase().split('').sort();
let count = 0;
let duplicateCount = (parm1) => {
for (var i = 0; i < sorted_arr.length - 1; i++) {
if (sorted_arr[i + 1] == sorted_arr[i]) {
count ++;
}
} return count;
}
duplicateCount(arr);
Count returns 7, what is expected is 2. Also, I would really like to avoid using a for loop. I'm hoping this can be done with .forEach or something method. ** I'm still pretty knew to code so please try not to do any one liners :) I appreciate the efficiency, but I'm still trying to understand the logic
You can use reduce and filter
Change string to lowercase
Split string by ''
Use each element as key, if it is already present increase it's count by 1 else set it to 1
Filter values which are greater than 1 to see duplicates
Get length of filtered array
var str = 'Indivisibilities';
let duplicateCount = (str) => {
let dups = str.toLowerCase().split('').reduce((op,inp)=>{
op[inp] = op[inp] || 0
op[inp]++
return op
},{})
return Object.values(dups).filter(v=>v>1).length
}
console.log(duplicateCount(str));
I am trying to sum up the numbers inside an array e.g. from here: https://jsfiddle.net/4r8dtxhz/12/
here is the Code:
var someObj = [{name:"hi", series: [1,2,10,4,5,6]},{name:"ho",series:[3,7,6,9,12,1,3,20,3,1]}]
for (var doc of someObj) {
this.min = doc.series.reduce((agg,val) => val < agg? val:agg, doc.series[0]);
this.max = doc.series.reduce((agg,val) => val > agg? val:agg, doc.series[0]);
}
console.log(max)
var test = Array.from(someObj.map((doc)=>doc.series)).reduce((accumulator, currentValue) => accumulator + currentValue);
console.log(typeof test)
console.log(test)
I was expecting the reduce function to sum up the numbers in the object series array... so I am wondering what goes wrong here?
Your map function is producing an two dimensional array of [someObj[0].series, someObj[1].series].
When you add two arrays together using the + operator in your reducer, it converts them to a string and concatenates the string.
If you want to create an array of the sum of each series, introduce another map function which has a reduce inside it.
You are missing a step to flatten the result of your map step. Your code
someObj.map((doc) => doc.series)
will return an array of arrays (or 2D array) rather than a flat array.
If you add a step to flatten the 2D array after your map step—for example by
.reduce((flattened, series) => flattened.concat(series))
using Array.reduce again—you will get the expected result.
Note that you should always provide an initial value for the accumulator of reduce (in your case 0 was missing for the summation) to assure that + is getting resolved correctly to number addition (otherwise it will be string concatenation, e.g. [1]+[2] === '12').
Also, Array.from wasn't necessary since someObj already is an array (Array.from converts from an Iterable object to Array).
var someObj = [{name:"hi", series: [1,2,10,4,5,6]},{name:"ho",series:[3,7,6,9,12,1,3,20,3,1]}]
for (var doc of someObj) {
this.min = doc.series.reduce((agg,val) => val < agg? val:agg, doc.series[0]);
this.max = doc.series.reduce((agg,val) => val > agg? val:agg, doc.series[0]);
}
console.log(max)
var test = someObj.map((doc)=>doc.series)
.reduce((flattened, series) => flattened.concat(series))
.reduce((accumulator, currentValue) => accumulator + currentValue, 0);
console.log(typeof test)
console.log(test)
var strings = [ '234-496-7459', '760-644-0201', '555-222-3333' ];
var ints = [];
console.log(strings);
strings.forEach(function(entry) {
var ints = entry.replace(/-/g, '');
console.log(ints);
});
var myResults = ints.map(function (el) {
return el.toString().split('').reduce(function (sum, b) {
return sum + +b;
}, 0);
});
console.log(myResults);
I have an array of strings that I want to take out the dashes then store the new arrays as ints. I am trying to reduce each array of ints to create a myResults that print out 53, 30, 33. I know there is something wrong with this code because the mapping and reduce doesn't want to work.
You need to push entry values in ints array after replace
var strings = [ '234-496-7459', '760-644-0201', '555-222-3333' ];
var ints = [];
strings.forEach(function(entry) {
ints.push(entry.replace(/-/g, ''));
});
var myResults = ints.map(function (el) {
return el.toString().split('').reduce(function (sum, b) {
return sum + +b;
}, 0);
});
alert(myResults);
You can combine your statements like this (in a working snipppet):
var strings = [ '234-496-7459', '760-644-0201', '555-222-3333' ];
var ints = strings.map(function(item) {
return item.replace(/-/g, '').split('').reduce(function(total, val) {
return total + +val;
}, 0);
});
document.write(JSON.stringify(ints));
Explanation:
You want to convert one array to another so use .map() not .forEach().
Then, right in the .map() callback, you can convert the string to total.
.replace(/-/g, '').split('') gets rid of the dashes and turns it into an array of letters.
.reduce() then runs on that array to sum up all the digits.
If you're looking for another way, you can use
Array#map, String#replace, String#split, Array#reduce with Arrow function syntax.
You can use RegEx /\d/g with String#match to get individual numbers as an array.
var ints = arr.map(el => el.match(/\d/g, '').reduce((sum, a) => sum + +a, 0));
\d matches a single digit. g is global flag, to get all the possible matches.
var arr = ['234-496-7459', '760-644-0201', '555-222-3333'];
var ints = arr.map(el => el.match(/\d/g, '').reduce((sum, a) => sum + +a, 0));
console.log(ints);
document.write(ints);
String#replace and String#split can also be used.
var ints = arr.map(el => el.replace(/-/g, '').split('').reduce((sum, a) => sum + +a, 0));
var arr = ['234-496-7459', '760-644-0201', '555-222-3333'];
var ints = arr.map(el => el.replace(/-/g, '').split('').reduce((sum, a) => sum + +a, 0));
console.log(ints);
document.write(ints);
Equivalent code in ES5
var ints = arr.map(function (el) {
return el.replace(/-/g, '').split('').reduce(function (sum, a) {
return sum + +a;
}, 0);
});
var arr = ['234-496-7459', '760-644-0201', '555-222-3333'];
var ints = arr.map(function(el) {
return el.replace(/-/g, '').split('').reduce(function(sum, a) {
return sum + +a;
}, 0);
});
console.log(ints);
Approach this in top-down fashion, step-by-step. For each step, we will write a little spec so we are perfectly clear on what we want to do. If we write the spec well, then the JS will follow easily.
We want to write a function sum_digits_of_array, for which the spec is:
sum_digits_of_array
Given an input array, return a new array, where each element is the sum of the digits of the corresponding element from the original array.
That is exactly the definition of map, so we can write:
function sum_digits_of_array(a) { return a.map(sum_digits); }
Now we just need to write sum_digits. We will also write a spec for that:
sum_digits
Given an input string, return the sum of the digits of the string.
That's easy enough:
function sum_digits(s) { return sum(digits(s)); }
Now for digits. Again we will write a little spec for ourselves:
digits
Given a input string, return array of individual digits, as numbers.
Instead of thinking of this as removing dashes and then splitting, we will use RegExp#match to just extract the digits:
function digits(s) { return s.match(/\d/g) . map(Number); }
Then
sum
Given an array of numbers, return the sum of all the numbers.
This is the definition of reduce, so
function sum(a) { return a.reduce(add); }
Then
add
Given two numbers, return the result of adding them
function add(a, b) { return a + b; }
That's it. So the entire solution, which is slightly more compact if we use ES6 arrow functions:
function sum_digits_of_array(a) {
const sum_digits = s => sum(digits(s));
const digits = s => s.match(/\d/g) . map(Number);
const sum = a => a . reduce(add);
const add = (a, b) => a + b;
return a . map(sum_digits);
}
Why code in this fashion? There are a number of good reasons.
You can read the code and tell what it's doing.
Related to that, it's easy to figure out where to modify the code if the problem changes.
We can easily test each little function to make sure it's working right.
The little functions we wrote might come in handy when solving a related problem, so we reduce the amount of work we have to do in the future.