Functions to combine elements of differents arrays? - javascript

I have a problem here, with the arrays. So. I have 3 arrays:
const names = [Robert, Mark, Lindsay, Anna, Erin, Andrew]
const surnames = [Smith, Black, White, Lewis, Cooper, Hill]
const ages = [21, 14, 19, 28, 65, 31]
I must create 2 functions :
On will give me a new array with the couples man-woman (like Robert-Anna / Erin-Mark etc.);
And one must give a me a new array with the name, the surname and the age (like Robert Smith 21, Mark Black 14, etc.).
So, what I think for the first function was to do this randomly:
function getElementFromArray(arr) {
const min = 0;
const max = (arr.length);
const randIndex = Math.floor(Math.random() * (max - min));
return arr[randIndex];
}
const boyArray = Array("Robert", "Mark", "Andrew");
const boy = getElementFromArray(boyArray);
const girlArray = Array("Erin", "Anna", "Lindsay");
const girl = getElementFromArray(girlArray);
const getPair = [boy + girl];
But this is not a function, so I must to transform this into a function. And this thing gives me only one couple of Man+Woman, but i need 3 couples that must to be written in an Array form.
For the second function, i really don't now how to write it. Thinked about something like:
const nameSurnameAge = [names.slice (0, 1) + surnames.slice (0, 1) + ages.slice (0, 1)] + [names.slice (1, 2) + surnames.slice (1, 2) + ages.slice (1, 2)]
But again: this is not a function (and i need to transform this thing into a function) and it's very-very long.
Can somebody help me please?
Thank You!

Use arrays of men and women. Assuming there are an equal number of men and women.
const names = ["Robert", "Mark", "Lindsay", "Anna", "Erin", "Andrew"]
const surnames = ["Smith", "Black", "White", "Lewis", "Cooper", "Hill"]
const ages = [21, 14, 19, 28, 65, 31]
const genders = ["M", "M", "F", "F", "F", "M"]
var arrNew = [];
var people = [];
function fnBuildNewArray(){
for (var i=0; i<names.length; i++) {
people[i] = {
name: names[i],
surname: surnames[i],
age: ages[i],
gender: genders[i],
partner: "single"
};
arrNew[i] = people[i]["name"]+" "+people[i]["surname"]+" is "+people[i]["age"];
}
}
function fnBuildCouples(){
var iMen = [];
var iWomen = [];
var m=0;
var w=0;
// collect men and woman
for (var i=0; i<names.length; i++) {
if(people[i]["gender"]=="M"){
iMen[m] = i;
m++;
}
else
{
iWomen[w] = i;
w++;
}
}
// This is where the magic happens
// Shuffle the Women
let iWomenshuffled = iWomen
.map(value => ({ value, sort: Math.random() }))
.sort((a, b) => a.sort - b.sort)
.map(({ value }) => value);
var offset=0;
// assign the partners
for (var i=0; i<people.length; i++) {
if(people[i]["gender"]=="M"){
var z = iWomenshuffled[offset];
people[i]["partner"] = people[z]["name"];
people[z]["partner"] = people[i]["name"]
offset++;
}
}
}
function fnProcess(){
fnBuildNewArray();
fnBuildCouples();
console.log(JSON.stringify(arrNew));
console.log(JSON.stringify(people));
}
<button onclick="fnProcess()">Process</button>

Related

How to create array of objects through map?

I would like to have multiple arrays of objects like this.
E.g:
const pets = [
{
name: "cat",
age: 4
},
{
name: "dog",
age: 6
}
]
But I want to create it using a map. So I was trying something like this.
let pets = [];
pets.map((item) => {
return (
item.push({
name: "cat",
age: 4
}, {
name: "dog",
age: 6
})
)
})
By this method, I'm getting an empty array.
So assuming this is incorrect, how would I go on and make this through a map.
Please any help would be appreciated.
first of all map works by looping through an array but you have empty array let pets = []; so the loop doesn't even start ! that's why you are getting empty array
Secondly map essentially is a method through which we can create a new array with the help of an existing array so you have chosen a wrong way!
example of map
const fruits = ["Mango", "Apple", "Banana", "Pineapple", "Orange"];
console.log(fruits);
const uppercaseFruits = fruits.map((fruit)=>{
return fruit.toUpperCase(); // this thing will be added to new array in every iteration
});
console.log(uppercaseFruits);
but still ....
let pets = [""]; // an item so that loop can start
const myPets = pets.map((item) => {
return (
([{
name: "cat",
age: 4
},{
name: "dog",
age: 6
}])
)
})
console.log(myPets)
//Usage of map: for example
let array = [1, 2, 3, 4, 5];
let newArray = array.map((item) => {
return item * item;
})
console.log(newArray) // [1, 4, 9, 16, 25]
map will not change the original array, if you don't assign a value to it, the original array will never be affected
And if you want to get what you want you use RANDOM like this
//random String
function randomString(e) {
e = e || 32;
var t = "ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678",
a = t.length,
n = "";
for (i = 0; i < e; i++) n += t.charAt(Math.floor(Math.random() * a));
return n
}
//random Number
function GetRandomNum(Min,Max)
{
var Range = Max - Min;
var Rand = Math.random();
return(Min + Math.round(Rand * Range));
}
var num = GetRandomNum(10000,999999);
alert(num);
Then you can combine random strings and random numbers into a new Object through a function

Find the highest scoring word from a string according to its position in the alphabet using JavaScript

I am trying to solve CodeWars challenges but I have a problem with this one:
"Given a string of words, you need to find the highest scoring word.
Each letter of a word scores points according to its position in the alphabet:
a = 1, b = 2, c = 3 etc.
You need to return the highest scoring word as a string.
If two words score the same, return the word that appears earliest in the original string.
All letters will be lowercase and all inputs will be valid."
My code passed 104 cases but got wrong on 1 case.
The wrong answer test case is
'what time are we climbing up the volcano'
According to codewars - Expected: 'volcano', instead got: 'climbing'
Any ideas?
link of the problem - https://www.codewars.com/kata/57eb8fcdf670e99d9b000272/train/javascript
function high(x){
let result = '', value =0, counterValue = 0;
let splittedArray = x.split(' ');
splittedArray.map(splitItem => {
counterValue = 0;
let splitItemArray = splitItem.split('');
splitItemArray.map(splitChar => {
counterValue += splitChar.charCodeAt();
})
if(counterValue>value){
result = splitItem;
value = counterValue;
}
});
return result;
}
function high(x) {
const words = x.split(' ');
const alphabetMap = {};
for (let i='a'.charCodeAt(), j = 1; i <= 'z'.charCodeAt(); i++, j++) {
alphabetMap[i] = j;
}
let highestScoringWord = { word: '', score: 0 };
words.forEach(w => {
const chars = w.split('');
const sumOfChars = chars.reduce((count, char) => count + alphabetMap[char.charCodeAt()], 0);
if (sumOfChars > highestScoringWord.score) {
highestScoringWord = { word: w, score: sumOfChars };
}
});
return highestScoringWord.word;
}
console.log(high('what time are we climbing up the volcano')) // volcano ;)
You can use reduce and object to keep track of highest count and respective word
function high(x){
let mapper = [...`abcdefghijklmnopqurstuvwxyz`].reduce((op,inp,index)=>{
op[inp] = index+1
return op
},{})
return x.split(' ').reduce((op,inp)=>{
let currentCount = 0;
[...inp].forEach(v=>{
currentCount += mapper[v]
})
if(currentCount > op.maxCount){
op.maxCount = currentCount
op.word = inp
}
return op
}, {maxCount:0, word:''}).word
}
console.log(high('what time are we climbing up the volcano'), 'volcano'))
the solution is to use an array of the alphabet and indexing the character position in it,
let al = `abcdefghijklmnopqrstuvwxyz`.split('')
function high(x){
let words = x.split(" ");
let out = words.map(word => {
let score = 0;
let letters = word.split("");
letters.map(c => {
score += al.indexOf(c);
})
return [word, score];
});
out = out.sort((a,b) => {
if(a[1] > b[1]) return -1;
else if(a[1] < b[1]) return 1;
else return 0; });
return out[0][0];
}
I'm confused by your counterValue += splitChar.charCodeAt(); line. I don't understand how splitChar.charCodeAt() translates into 1-26 aka a letters position in the alphabet. "Each letter of a word scores points according to its position in the alphabet"
I was able to able to make your code work by doing two things:
Add a map to store the value of each letter in the alphabet. I'm sure this can be done many ways but this was my approach:
let letterValues = { a: 1, b: 2, c: 3, d: 4, e: 5, f: 6, g: 7, h: 8, i: 9, j: 10, k: 11, l: 12, m: 13, n: 14, o: 15, p: 16, q: 17, r: 18, s: 19, t: 20, u: 21, v: 22, w: 23, x: 24, y: 25, z: 26 };
And then use this in counterValue += splitChar.charCodeAt(); as counterValue += letterValues[letter];
Idea:
Store the score values in a table for easy lookup
split sentences into words by non-alphabetic characters
get each word's score by first calculating the individual characters' scores and then summing them together (using reduce).
Don't forget to sort by original position if scores are the same, do it by keeping track of the original position.
Demo: https://jsfiddle.net/9xkfqh1m/
const ScoreTable = {
"a": 1,
"b": 2,
"c": 3,
"d": 4,
"e": 5,
"f": 6,
"g": 7,
"h": 8,
"i": 9,
"j": 10,
"k": 11,
"l": 12,
"m": 13,
"n": 14,
"o": 15,
"p": 16,
"q": 17,
"r": 18,
"s": 19,
"t": 20,
"u": 21,
"v": 22,
"w": 23,
"x": 24,
"y": 25,
"z": 26
};
// non-ascii letters = 0
function CharScore(char) {
const lowerCaseChar = char.toLowerCase();
return lowerCaseChar in ScoreTable ? ScoreTable[lowerCaseChar] : 0;
}
function WordScore(word) {
return word.split("").reduce((score, char) => {
return score + CharScore(char);
}, 0);
}
function SplitOnNonAlphabeticCharacters(str) {
return str.split(/[^a-zA-Z]+/gm);
}
function high(str){
const scoreObjects = SplitOnNonAlphabeticCharacters(str) // split into words
.map((word, index) => { // map our words into an object with its score and original position
return {
text: word,
score: WordScore(word),
originalPosition: index
};
}).sort((word1, word2) => { // sort
return word2.score - word1.score // highest score first
|| word1.originalPosition - word2.originalPosition; // if score same, earliest original position in string
});
return scoreObjects.length > 0 ? scoreObjects[0].text : null; // return word by the highest score (or earliest original position), or null
}
The charCodeAt() method returns an integer between 0 and 65535 representing the UTF-16 code unit at the given index.
Basically you need to convert it to an uppercase alphabet and subtract the value of the charCodeAt by 64 which will give you the position of the string in the alphabet.
Check this one out:
function high(x) {
let splittedArray = x.split(' ');
let splitChar = splittedArray.map(el => el.split(''));
let charValue = splitChar.map(el => {
let counter = 0;
el.map(element => counter += element.toUpperCase().charCodeAt() - 64);
return counter;
});
let largest = 0;
let largestIndex;
for (let i = 0; i < charValue.length; i++) {
if (charValue[i] > largest) {
largest = charValue[i];
largestIndex = i;
}
}
return splittedArray[largestIndex];
}
I made a mistake by not counting letters position in the alphabet. If I subtract 96 from ASCII value then it will calculate a as 1, b as 2......
So the solution is given below
function high(x){
let result = '', value =0, counterValue = 0;
let splittedArray = x.split(' ');
splittedArray.map(splitItem => {
counterValue = 0;
let splitItemArray = splitItem.split('');
splitItemArray.map(splitChar => {
counterValue += splitChar.charCodeAt()-96; // if I subtract 96 then it will calculate a as 1, b as 2......
})
if(counterValue>value){
result = splitItem;
value = counterValue;
}
});
return result;
}
function high(x){
const str = x.split(' ');
const result1 = [];
const result = str.reduce((_, dig) => {
let c = 0;
for (let j = 0; j < dig.length; j++) {
c = c + (dig.charCodeAt(j) - 96);
}
result1.push(c);
}, 0);
return str[result1.indexOf(result1.slice().sort((a, b) => b - a)[0])];
}
Thought I'd post since I solved it, even though the post is pretty old. Anyway this was solved from pure javascript.
//This main function loops thru each sum from the helper function and returns the position of the highest scoring word
function highestScoringWord(sentence) {
let arr = []
let sentenceSplit = sentence.split(' ')
for(i=0; i<sentenceSplit.length; i++) {
arr.push(scoringWord(sentenceSplit[i]))
}
let max = arr[0]
for(x=0; x<arr.length; x++) {
if(arr[x] > max) {
max = arr[x]
}
}
for(p=0; p<arr.length; p++) {
if(max === arr[p]) {
return sentenceSplit[p]
}
}
}
//Helper function that takes a word, splits it, and sums up the numbers that each letter is worth.
function scoringWord(word) {
let wordSplit = word.split('')
let alphabet = 'abcdefghijklmnopqrstuvwxyz'
let sum = 0
for(j=0; j<word.length; j++) {
sum+=alphabet.indexOf(word[j])
}
return sum
}
function high(x){
const ScoreTable = ["0", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k","l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w","x", "y", "z"];
return x.split(" ").map(word => {
let code = 0
word.split("").map(letter => code += ScoreTable.indexOf(letter))
return [word, code]
}).sort((a,b) => b[1] - a[1])[0][0]
}

javascript map and reduce array list

I have a list of array in this format
data = [[1,2,3,4,5,6,7,8,9,10],
[11,12,13,14,15,16,17,18,19,20],
[21,22,23,24,25,26,27,28,29,30]]
I want the output in this format
[[11/1, 12/2,13/3,14/4,15/5,16/6,17/7,18/8,19/9,20/10],
[21/11,22/12,23/13,24/14,25/15,26/16,27/17,28/18,29/19,30/20]]
I have used for loop and this is how it looks
const totalData = data.length;
for(var i =0 ; i < totalData ; i++){
for(var j =0; j < data[i].length; j++){
console.log(data[i+1][j]/data[i][j]);
}
}
I want to convert this using javascript map and reduce? is there any possible ways?
Thank you
for loops aren't bad practice, they just don't fit in a functional style of programming. The following solution presupposes that the arrays' lengths are equal:
const data = [
[1,2,3,4,5,6,7,8,9,10],
[11,12,13,14,15,16,17,18,19,20],
[21,22,23,24,25,26,27,28,29,30]
];
const result = data.map((arr, index) => {
const next = data[index + 1];
if (!Array.isArray(next)) {
return;
}
return arr.map((item, i) => next[i] / item);
}).filter(Boolean);
console.log(result);
I am sure you can figure out what to do if the arrays' lengths are not equal.
You could use a single reduce and map the items for a new array.
var data = [[1, 2, 3, 4, 5, 6, 7, 8, 9, 10], [11, 12, 13, 14, 15, 16, 17, 18, 19, 20], [21, 22, 23, 24, 25, 26, 27, 28, 29, 30]],
result = [];
data.reduce((a, b) => (result.push(a.map((c, i) => b[i] / c)), b));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
You need to create separated functions for each task:
/**
* Combine 2 arrays
* #param Array a
* #param Array b
*/
function combineArrays(a, b) {
var combined = [];
for (var i = 0; i < a.length; i++)
combined.push(a[i] / b[i]);
return combined;
}
/**
* Combine an group of arrays
* #param Array group
*/
function combineGroup(group) {
var newGroup = [];
for (var i = 0; i < group.length - 1; i++)
newGroup.push(combineArrays(group[i], group[i + 1]));
return newGroup;
}
The first function combine 2 arrays only.
The second function combine many arrays and return what you want.
if the lengths are not equal, the items in the tail of the longer one are ignored.
data = [
[1,2,3,4,5,6,7,8,9,10],
[11,12,13,14,15,16,17,18,19,20],
[21,22,23,24,25,26,27,28,29,30]
];
result = data.reduce((acc,current,i)=>{
var ret;
if(data[i].length <= data[i-1].length)
ret = data[i].map((item,j)=>(item / data[i-1][j]));
else
ret = data[i-1].map((item,j)=>(data[i][j] / item));
if(i==1)
return [ret]
else
return acc.concat([ret])
})
console.log(result)

filtering and averaging values in one array based on values in a second array

I have two separate arrays: one with the hour at which the measurement was performed and one with the results obtained at that hour. Example: (the real data is much longer)
hours =[10,8,13,7,8,12,10,13,23,12]
results =[101, 104, 101, 106, 101, 107, 109, 110, 112, 107]
I plot one against the other and now I need to find the average for each hour. At first I thought this to be a trivial thing to do but it got complicated real fast. I bet there is an easy way to do it, I just can't find it. I searched couple of related questions about it and came up with a solution below. It works but it is slow and surely there is a way to do it better. (Note that for plotting I need to end up with sorted arrays for unique hours and equivalently sorted array containing the averages for each hour).
function ave (a) {
var total = 0;
for(var i = 0; i <= a.length-1; i++) {
total += a[i];
}
return total / a.length;
}
var unique = Array.from(new Set(hours));
unique.sort(function(a, b){return a-b});
var arr_res= [];
var build_arr =[];
for (var i = 0; i <= unique.length-1; i++) {
build_arr.length = 0;
for (var j = 0; j <= results-1; j++) {
if (hours[j] == unique[i]) {
build_arr.push(results[j]);
}
}
arr_res.push(ave(build_arr));
}
1. Iterate over hours array
2. Create an object that would have at it's key the value of hour
3. The value would be the value from results array when you are adding the key first time.
4. When that same key is found subsequently, the average is computed and added as modified value.
5. Push the obj values into an array by iterating the object
6. Sort the array by hour. If this array is enough stop else collect the result in two arrays.
See the solution below:
var hours = [10, 8, 13, 7, 8, 12, 10, 13, 23, 12];
var results = [101, 104, 101, 106, 101, 107, 109, 110, 112, 107];
var obj = {};
var avg = 0,
tempCount;
hours.forEach(function(v, i) {
if (!obj[v]) {
obj[v] = {
hour: v,
val: results[i],
count: 1
};
} else {
tempCount = obj[v].count + 1;
avg = (obj[v].val + results[i]) / tempCount;
obj[v] = {
hour: v,
val: avg,
count: tempCount
};
}
});
//You have got averages by now. //Only thing remaining is to get the right output //data structures.
var res = [];
for (var i in obj) {
if (obj.hasOwnProperty(i)) {
//console.log("Key=" + i, "Val=" + obj[i].val);
res.push(obj[i]);
}
}
res = res.sort(function(a, b) {
return a.hour - b.hour;
});
var hourRes = [],
avgRes = [];
res.forEach(function (v, i) {
hourRes.push(v.hour);
avgRes.push(v.val);
});
console.log(hourRes, avgRes);
You can do it something like this by combining Array.reduce(), Array.map() and Object.keys() :
var hours =[10,8,13,7,8,12,10,13,23,12];
var results =[101, 104, 101, 106, 101, 107, 109, 110, 112, 107];
var groups = hours.reduce(function(acc, hour, idx) {
acc[hour] = acc[hour] || [];
acc[hour].push(results[idx]);
return acc;
}, {});
//console.log(groups);
var averages = Object.keys(groups).sort(function(a, b) {
return a-b;
}).map(function(key) {
return groups[key].reduce(function(sum, val) {
return sum+val;
}) / groups[key].length;
});
console.log(Object.keys(groups).sort(function(a, b){return a - b;}));
console.log(averages);
If I understand the question correctly then the following should work:
Output for the following is :
**
7-106, 8-102.5, 10-105, 12-107, 13-105.5, 23-112
**
var hours = [10, 8, 13, 7, 8, 12, 10, 13, 23, 12];
var results = [101, 104, 101, 106, 101, 107, 109, 110, 112, 107];
function toObject(names, values) {
var result = [];
for (var i = 0; i < names.length; i++)
result.push({ hour: names[i], result: values[i]});
return result;
}
function average(arr) {
var sums = {}, counts = {}, results = [], name;
for (var i = 0; i < arr.length; i++) {
name = arr[i].hour;
if (!(name in sums)) {
sums[name] = 0;
counts[name] = 0;
}
sums[name] += arr[i].result;
counts[name]++;
}
for(name in sums) {
results.push({ name: name, value: sums[name] / counts[name] });
}
return results;
}
function Test() {
var result = toObject(hours, results);
var averagess = average(result);
for (var i = 0; i < averagess.length; i++) {
console.log(averagess[i].name + '-' + averagess[i].value);
}
}

Calculate the average of points in a array - Javascript

I have an array with infos about a group of people : name, current status, new points, last event points
Example:
var group = new Array();
group[0] = "John Doe,beginer,14,7";
group[1] = "Lois Lane,advanced,13,9";
group[2] = "Bruce Waine,advanced,17,10";
I need a function that calculates the average of the new points.
For the previous example the average would be (14+13+17)/3 = 14.66666666666667
It'd be a heck of a lot easier if you convert the data in the array from strings to objects This will benefit you in two ways: 1) the code will be more readable, understandable, and easier to maintain, and 2) you won't have to do a bunch of string gymnastics to pull out the relevant data.
Do something like this:
var group = [
{ name: 'John Doe', status: 'beginner', newPoints: 14, eventPoints: 7 },
{ name: 'Lois Lane', status: 'advanced', newPoints: 13, eventPoints: 9 },
{ name: 'Bruce Waine', status: 'advanced', newPoints: 17, eventPoints: 10 }
];
function getAverageNewPoints(people) {
var count = people.length || 0,
average = 0;
for (var i = 0; i < count; i++) {
average += people[i].newPoints;
}
return average / count;
}
alert('The average of new points in the group is: ' + getAverageNewPoints(group));
Try the following:
function groupAverage(group) {
var sum = 0;
var count = group.length;
for (var i in group) {
sum += parseInt(group[i].split(',')[2], 10);
}
return sum / count;
}
Split the String at , and get the values and convert them to Number.
var group = new Array();
group[0] = "John Doe,beginer,14,7";
group[1] = "Lois Lane,advanced,13,9";
group[2] = "Bruce Waine,advanced,17,10";
sum=0;
for(var i in group)
{
sum=sum+Number(group[i].split(",")[2]);
}
console.log(sum/group.length);
You have a bad data structure for this. You don't want to use strings. You also should not use the Array constructor. Start with:
var group = [
{name: "John Doe", rank: "beginner", points: 14, lastScore: 7},
{name: "Lois Lane", rank: "advanced", points: 13, lastScore: 9},
{name: "Bruce Wayne", rank: "advanced", points: 17, lastScore: 10},
],
length = group.length,
sum = 0,
i;
for ( i = 0; i < length; ++i) {
sum += group[i].points;
}
return sum / length; // Or do something else with the result.
// I did no error checking.
You could use an object constructor instead of the inline Object I used, but that's not really necessary. I'm just curious; did you use strings as a default, or was using a string interface part of a textbook assignment?
Oh, one reason to use [] instead of new Array() is that when you construct an Array, the value is always truthy, while [] is falsy.
I did take the liberty of correcting Bruce's last name.

Categories

Resources