I've already did this using a loop but our instructor said that it can be done with a shorter and simpler method/function. We are not allowed to use for loops or foreach. We can only use es6 related code.
This is my code.
var total = 0
let givenWord = "cabbage"
let pointsTable = new Map([['a',1],['e',1],['i',1],['o',1],['u',1],['l',1],['n',1],['r',1],['s',1],['t',1],
['d',2],['g',2],['b',3],['c',3],['m',3],['p',3],['f',4],['h',4],['v',4],['y',4],['k',5],['j',8],['x',8],['q',10],['z',10]])
for(let [...letters] of givenWord){
for(let [key,value] of pointsTable){
if(letters == key){
total = total + value;
console.log("Total value is " + total)
}
}
}
my problem here is that my loops take up too many lines of code. How do I transform this one into simpler code or using a function/method ? using only ES6?
Ok, I created a sort ES6 way to return the chars in an array and run a check function on them:
const pointsTable = new Map([['a',1],['e',1],['i',1],['o',1],['u',1],['l',1],['n',1],['r',1],['s',1],['t',1],
['d',2],['g',2],['b',3],['c',3],['m',3],['p',3],['f',4],['h',4],['v',4],['y',4],['k',5],['j',8],['x',8],['q',10],['z',10]])
// With ES6
const text= 'abcdefg';
const result = [...text].reduce((acc, cur) => {
return acc + pointsTable.get(cur)
}, 0);
console.log(result);
An other way you could do this is write a while loop and use the String.split(), String.slice() or String.substring() methods to reduce the string to the chars
You can use recursion for this task:
var total = 0
let givenWord = "cabbage"
let pointsTable = new Map([['a',1],['e',1],['i',1],['o',1],['u',1],['l',1],['n',1],['r',1],['s',1],['t',1],
['d',2],['g',2],['b',3],['c',3],['m',3],['p',3],['f',4],['h',4],['v',4],['y',4],['k',5],['j',8],['x',8],['q',10],['z',10]])
const countTotal = (arr, map, points = 0) => {
if(arr.length === 0) return points
points += map.get(arr.splice(0,1)[0])
return countTotal(arr, map, points)
}
console.log(countTotal([...givenWord],pointsTable))
Using the split method it will separate the text into the individual letters. Then you can use the map method to iterate through each of those letters and do a check within that.
const test = 'abcdefg'
let total = 0;
let pointsTable = new Map([['a',1],['e',1],['i',1],['o',1],['u',1],['l',1],
['n',1],['r',1],['s',1],['t',1],
['d',2],['g',2],['b',3],['c',3],['m',3],['p',3],['f',4],['h',4],['v',4],
['y',4],['k',5],['j',8],['x',8],['q',10],['z',10]])
test.split('').map(function(letter){
let value = pointsTable.get(letter)
total += value;
});
Here's the shortest way I can think of :
var total = 0
let givenWord = "cabbage"
let pointsTable = new Map([['a',1],['e',1],['i',1],['o',1],['u',1],['l',1],['n',1],['r',1],['s',1],['t',1],
['d',2],['g',2],['b',3],['c',3],['m',3],['p',3],['f',4],['h',4],['v',4],['y',4],['k',5],['j',8],['x',8],['q',10],['z',10]])
let total = givenWord.split``.reduce((a,l)=>a+pointsTable.get(l),0)
console.log("Total value is " + total)
details :
let total = // assign to total
givenWord // the givenword
.split`` // splited to get an array of characters
.reduce( // call reduce on the array
(a, l) => { // first arg of reduce is a function
// called for each elements of the array
// arguments are the accumulator, the letter
a + pointsTable.get(l) // add the letter score to the accumulator
},
0 // set default value of accumulator (2nd arg of reduce)
)
fn`` documentation (look at section tagged template),
reduce documentation
Related
I try to solve task below with reduce() and actually the result is ok. But I don't know how to use acc in reduce() instead of acc1 or indexMax.
How to apply typescript to this task.
The task:
Find first word with max repeated letter count. For example rrrtygggg and ttbvfddjklyyyaseqq - the winner is rrrtygggg.
If sequence has no repeated letters return 'false'.
Count only letters, ignor digits and special chars.
Here is my solution.
Also I need to keep time complexity not higher than n. The most important part for me is reduce() and acc.
const maxLettersInString =(str)=>{
let acc1={};
let indexMax;
let ind=0;
let n=0;
const newStr = str.replace(/[^a-z\s]/gi,'')
const arr = str.split(' ');
if(arr.length===0) return false;
const arr1 = newStr.split('');
const result = arr1.reduce((acc,x)=>{
if(x!==' '){
acc1[x] ? acc1[x]++ : acc1[x] = 1;
if(acc1[x]>n) n=acc1[x], indexMax=ind;
}
if(x===' ') acc1={}, ind+=1;
else return indexMax;
})
if(n===1) return false
return arr[result]
}
console.log(maxLettersInString('fdsJJHHBldfkfd +=dfsfds tbrlllLLtrbtrbrLL666667777LLtlllllll----- fdsfs66df7758 tRbrerbrrtRR'));
Iterate over the original words, with two outer variables:
One with a count of the maximum number of repeated letters found so far (starts at 0), and
The string corresponding to the count found above
All you need is a simple loop - on each iteration, calculate the repeat count for the current word being iterated over, and if it's higher than the record so far, reassign the two outer variables.
const getRepeatCount = (str) => {
const repeatCounts = {};
for (const char of str.replace(/[^a-z]/gi, '')) {
repeatCounts[char] = (repeatCounts[char] ?? -1) + 1;
}
return Math.max(...Object.values(repeatCounts));
};
const maxLettersInString = (str) => {
let maxRepeatsFoundSoFar = 0;
let bestWordSoFar = '';
for (const word of str.split(' ')) {
const repeatCount = getRepeatCount(word);
if (repeatCount > maxRepeatsFoundSoFar) {
maxRepeatsFoundSoFar = repeatCount;
bestWordSoFar = word;
}
}
return bestWordSoFar === '' ? false : bestWordSoFar;
};
console.log(maxLettersInString('rrrtygggg and ttbvfddjklyyyaseqq'));
To turn it into TypeScript, just add : string to the parameter types and : Record<string, number> to the repeatCounts object.
This would be possible to do with .reduce if the accumulator was an object with two properties, maxRepeatsFoundSoFar and bestWordSoFar instead of outer variables - but the typing and syntax noise would be annoying, outer variables are easier.
I have a function that I have modified to get a string (which consists of zeros and ones only).
The string (timesheetcoldata):
100000000000000000000000100000000000000000000000100000000000000000000000100000000000000000000000100000000000000000000000100000000000000000000000
The string items (the numbers one and zero) will change every time the function is run.
It will always be the same length.
I have made the string above easier to see what I am trying to achieve.
I want to return the first character and then every 24th character (as in the variable colsCount in the function).
so, in the example above, it would return something like: 111111
I then want to convert these characters to numbers (something like [1, 1, 1, 1, 1, 1]).
I then want to sum these number together (so it would return, in the example: 6).
I then want to check if the returned number matches the variable: rowsCount
or true if it does, false if it does not.
My function:
$("#J_timingSubmit").click(function(ev){
var sheetStates = sheet.getSheetStates();
var rowsCount = 6;
var colsCount = 24;
var timesheetrowsdata = "";
var timesheetcoldata = "";
for(var row= 0, rowStates=[]; row<rowsCount; ++row){
rowStates = sheetStates[row];
timesheetrowsdata += rowStates+(row==rowsCount-1?'':',');
}
timesheetcoldata = timesheetrowsdata.replace(/,/g, '');
console.log(timesheetcoldata);
});
Thank you very much to both Rajesh and MauriceNino (and all other contributers).
With their code I was able to come up with the following working function:
$("#J_timingSubmit").click(function(ev){
var sheetStates = sheet.getSheetStates();
var rowsCount = 6;
var timesheetrowsdata = "";
var timesheetcoldata = "";
for(var row= 0, rowStates=[]; row<rowsCount; ++row){
rowStates = sheetStates[row];
timesheetrowsdata += rowStates+(row==rowsCount-1?'':',');
}
timesheetcoldata = timesheetrowsdata.replace(/,/g, '');
var count = 0;
var list = [];
for(var i = 0; i< timesheetcoldata.length; i+=24) {
const num1 = Number(timesheetcoldata.charAt(i));
list.push(num1);
count += num1;
}
let isSameAsRowsCount = count == rowsCount;
console.log('Is Same? ', isSameAsRowsCount);
});
You can always rely on traditional for for such action. Using functional operations can be more readable but will be more time consuming(though not by much).
You can try this simple algo:
Create a list that will hold all numbers and a count variable to hold sum.
Loop over string. As string is fixed, you can set the increment factor to the count(24).
Convert the character at given index and save it in a variable.
Push this variable in list and also compute sum at every interval.
At the end of this loop, you have both values.
var string = '100000000000000000000000100000000000000000000000100000000000000000000000100000000000000000000000100000000000000000000000100000000000000000000000';
var count = 0;
var list = [];
for(var i = 0; i< string.length; i+=24) {
const num1 = Number(string.charAt(i));
list.push(num1);
count += num1;
}
console.log(list, count)
Here is a step by step explanation, on what to do.
Use match() to get every nth char
Use map() to convert your array elements
Use reduce() to sum your array elements
Everything needed to say is included in code comments:
const testData = '100000000000000000000000100000000000000000000000100000000000000000000000100000000000000000000000100000000000000000000000100000000000000000000000';
// Step 1) Create array of numbers from string
const dataArr = testData.match(/.{1,24}/g) // Split on every 24th char
.map(s => Number(s[0])) // Only take the first char as a Number
console.log(dataArr);
// Step 2) Sum array Numbers
let dataSum = dataArr.reduce((a, b) => a + b); // Add up all numbers
console.log(dataSum);
// Step 3) Compare your variables
let rowsCount = 123; // Your Test variable
let isSameAsRowsCount = dataSum == rowsCount;
console.log('Is Same? ', isSameAsRowsCount);
As #Jaromanda mentioned, you can use the following to done this.
const string = '100000000000000000000000100000000000000000000000100000000000000000000000100000000000000000000000100000000000000000000000100000000000000000000000';
const value = string.split('').filter((e,i)=> !(i%24)).reduce((acc,cur)=> acc+ (+cur), 0);
console.log(value);
I want to find element from 3 arrays and create string using values. I have tried and given the output. But I want to know that, is there any better solution for this.
var numbers = ['1','2','3','4','5'];
var letters = ['A','B','C','D','E'];
var romans = ['I','II','III','IV','V'];
function findInArray(input){
var index = -1;
if(numbers.indexOf(input) >= 0){
index = numbers.indexOf(input);
} else if(letters.indexOf(input) >= 0){
index = letters.indexOf(input);
} else if(romans.indexOf(input) >= 0){
index = romans.indexOf(input);
}
if(index > -1){
var data = '{"numbers":"'+numbers[index]+'","letters":"'+letters[index]+'","romans":"'+romans[index]+'"}';
console.log(data);
}
}
findInArray('2');
output : {"numbers":"2","letters":"B","romans":"II"}
You don't need to check if indexOf exists for each of the arrays. You can just find the max value of index for all the three arrays.
If the argument exists in any of the array, it will return a positive values (which results in true)
Then you can simply return the concatenation of the result using the template strings
var numbers = ['1','2','3','4','5'];
var letters = ['A','B','C','D','E'];
var romans = ['I','II','III','IV','V'];
var findInArray = (i) => {
var index = Math.max(numbers.indexOf(i), letters.indexOf(i), romans.indexOf(i));
if (index) {
return `{numbers: ${numbers[index]}, letters: ${letters[index]}, romans: ${romans[index]}}`;
}
}
console.log(findInArray('2'));
console.log(findInArray('D'));
console.log(findInArray('V'));
Vishal,
#Jonas has used a self executing function.
For example it will output 25
(function(x){
return x*x;
}(5));
here 5is the parameter of this self executing function which will output to 25
Back to answer; When you convert his answer to raw it will look something like
const findInArray = val => (i => ({ //i = 1 here
numbers: numbers[1],
letters: letters[1],
romans: romans[1]
}))(Math.max(1,-1,-1) //will output 1);
Hope it makes sense.
resource - http://markdalgleish.com/2011/03/self-executing-anonymous-functions/
Might be simpler with:
const findInArray = val => (i => ({
numbers: numbers[i],
letters: letters[i],
romans: romans[i]
}))(Math.max(
numbers.indexOf(val),
letters.indexOf(val),
romans.indexOf(val)
));
I am trying to sum the contents of an array like these:
var cardsBen = [10,2]
var cardsAmy = [4,10]
When I use a for loop, it works.
for(var i = 0; i < cardsBen.length; i++){
cardsBen[i] = Number(cardsBen[i]);
}
When I use forEach, it doesn't convert.
cardsAmy.forEach(function(item)
{
Number(item);
});
I know this because, when I then reduce the arrays, I get 12 for Ben and 410 for Amy.
var sumBen = cardsBen.reduce(function(sum, nbr){return sum + nbr});
var sumAmy = cardsAmy.reduce(function(sum, nbr){return sum + nbr});
Primitive values can't be mutated. So when doing Number(item) you have to assign that back to the array like:
cardsAmy.forEach(function(item, i) {
cardsAmy[i] = Number(item);
});
And you can do that directly in reduce (without needing the above forEach code) like:
var sumBen = cardsBen.reduce(function(sum, nbr) { return sum + Number(nbr); }, 0);
// ^^^^^^^ ^
You could use reduce with an implicit casting to number with an unary plus +.
sum = array.reduce(function (s, v) {
return s + +v;
}, 0);
I am trying to get total count of all types and group based count of below json array.
var json = {"items":[
{"type":1,"count":10},
{"type":1,"count":10},
{"type":2,"count":20},
{"type":1,"count":30},
{"type":1,"count":40},
{"type":2,"count":100}
]
}
I want to get total count of all types (AllTypeTotal:210) and seperate count of type1(TypeOneTotal:90) and type2(TypeTwoTotal:120).
So I am expecting following array:
var json = {
"AllTypeTotal":210,
"TypeOneTotal":90,
"TypeTwoTotal":120
}
It can be done using Underscore's reduce or the native array.reduce. Here's an underscore solution:
var result = _.reduce(json.items, function(memo, item){
// build the correct key
var key = 'Type' + item.type + 'Total';
// update the total
memo.AllTypeTotal += item.count;
// update the type total
memo[key] = (memo[key] | 0) + item.count;
return memo;
}, { AllTypeTotal: 0 } );
I can help you with lodash which is a superset of underscore and much better than underscore when it comes to performance and consistency (see lodash vs underscore).
var uniqTypes = _.pluck(_.uniq(json.items, "type"), "type");
var result = {};
uniqTypes.forEach(function(typeName){
result["type"+typeName+"total"] = 0;
_.map(data.items, function(item){
if(item.type === typeName)
result["type"+typeName+"total"] += item.count;
});
});