After sorting an array of objects based on of their property values ("rating" in this case), how do you associate ranks for each object if there are ties between some of these values? Here's an example:
//Should be tied for 1st Rank
var obj1 = {
name: "Person1",
rating: 99
}
//Should be 3rd Rank
var obj2 = {
name: "Person2",
rating: 50
}
//Should be 2nd Rank
var obj3 = {
name: "Person3",
rating: 98
}
//Should be 4th Rank
var obj4 = {
name: "Person4",
rating: 0
}
//Should be tied for 1st Rank
var obj5 = {
name: "Person5",
rating: 99
}
Here's as far as I got:
var clients = [obj1, obj2, obj3, obj4, obj5];
var sorted = [];
for (var i = 0; i < clients.length; i++) {
sorted.push(clients[i]);
}
sorted.sort(function(a, b) {
return b.rating-a.rating;
});
Ultimately, I'd like to be able to get the rank using the object name, like this:
alert(sorted.indexOf(obj5) + 1);
Created a solution that worked, albeit ugly. Thanks jamie for some framework used in this:
for (var i = 0; i < clients.length; i++) {
sorted.push(clients[i]);
}
sorted.sort(function(a, b) {
return b.rating-a.rating;
});
for(var i = 0; i < sorted.length; i++) {
// original ranking
sorted[i].rank = i + 1;
}
function sortRanking() {
for (var k = 0; k < sorted.length; k++) {
for (var h = 1; h < sorted.length + 1; h++) {
if (sorted[k+h] !== undefined) {
if (sorted[k+h].tie !== true) {
if (sorted[k].rating === sorted[h + k].rating) {
sorted[k].rank = k + 1;
sorted[h + k].rank = k + 1;
sorted[k].tie = true;
sorted[h + k].tie = true;
}
}
}
}
}
}
sortRanking();
alert("Rank: " + obj3.rank);
Using ES6, here's how you can do it, adding a property rank to every client. Try the code snippet below.
function setRanks(clients) {
let currentCount = -1, currentRank = 0,
stack = 1; // consecutive clients with same rating
for (let i = 0; i < clients.length; i++) {
const result = clients[i];
if (currentCount !== result['rating']) {
currentRank += stack;
stack = 1;
} else {
stack++;
}
result['rank'] = currentRank;
currentCount = result['rating'];
}
}
// get the rank using the object name
function getRank(clientName) {
return clients.find(c => c.name === clientName)['rank'];
}
//Should be tied for 1st Rank
var obj1 = {
name: "Person1",
rating: 99
}
//Should be 3rd Rank
var obj2 = {
name: "Person2",
rating: 50
}
//Should be 2nd Rank
var obj3 = {
name: "Person3",
rating: 98
}
//Should be 4th Rank
var obj4 = {
name: "Person4",
rating: 0
}
//Should be tied for 1st Rank
var obj5 = {
name: "Person5",
rating: 99
}
var clients = [obj1, obj2, obj3, obj4, obj5];
clients.sort((c, other) => other.rating - c.rating);
setRanks(clients);
console.log(clients);
console.log(getRank('Person5'));
2nd attempt: although not quite there - i argue separating the ranking in to a different property rather than rely on the indexOf to find ranking is the way to go. You then have something clearer to manipulate when there is a tie. Still working it. Will be watching for best solution
for(var i = 0; i < sorted.length; i++) {
// original ranking
sorted[i].rank = i + 1;
}
function sortRanking() {
for(i=0; i< sorted.length; i++) {
var current = sorted[i];
var next = sorted[i + 1];
if(next === undefined || next.rating !== current.rating) {
console.log("we are done");
return "done";
}
if(next.rating === current.rating) {
for(var j = next + 1; j < sorted.length; j++) {
sorted[j].rank = sorted[j-1].rank;
}
next.rank = current.rank;
}
}
}
sortRanking();
console.log(sorted);
1st attempt - After playing around with for a bit. Here is a solution adding from your original logic:
var clients = [o1, o2, o3, o4];
var sorted = [];
for (var i = 0; i < clients.length; i++)
sorted.push(clients[i]);
sorted.sort(function (a, b) {
return clients.rating - clients.rating;
});
function checkForTieAndRating(x) {
// x parameter for object of interest
// need to get the one in front to determine if it is tied
// get index of obj of interest
var indexOfInterest = clients.indexOf(x);
var indexOfBefore = indexOfCurrent -1;
// if obj of interest is ranked #1 then return
if(indexOfBefore < 0) {
return indexOfInterest + 1;
} else {
// get the actual object before this one so you can check rating. put in variable so you can compare.
var objBefore = clients[indexOfBefore];
var ratingOfObjBefore = objBefore.rating;
if(ratingOfObjBefore === x.rating)
return "Tied for" + indexOfInterest;
}
}
// check ranking and if tie
checkForTieAndRating(obj2);
// other issue going this route - would be to then 1) alter the objects ranking following the objs that are tied - to
//Possible alternative solution: After working and about to submit it - I think it would be better to add a ranking property after the sort and manipulate the rankings from there if there are any tied.
If you want several records on the same place, you should probably use an additional immediate array, effectively grouping the elements.
I will use lodash for convinience, you should get the idea.
_.chain(clients).groupBy('rating').pairs().sortBy(0).reverse().pluck(1).value();
You loose your ability to use indexOf at this point, so you need to write your own getRank.
Again, with the help of lodash
// returns zero when no rank is found
var getRank = function(sortedArray, object) {
return 1 + _.findIndex(sortedArray, function(list) {
return _.contains(list, object);
});
};
Full working fiddle: http://jsfiddle.net/4WJN3/1/
I needed a similar piece of code for an operations scheduling script I was writing. I used objects and their properties/keys, which can have any value and can be accessed whenever needed. Also, as far as I read in some articles, the search of properties in objects can be faster than search in arrays.
The script below has three simple steps:
sort the values (ascending or descending doesn't matter for the rest of the script)
find the ranks and number of occurrences for each value
replace the given values with ranks using the data from step 2
Note! The below script will not output duplicate ranks, but instead increments ranks for duplicate values/elements.
function rankArrayElements( toBeRanked ) {
// STEP 1
var toBeRankedSorted = toBeRanked.slice().sort( function( a,b ) { return b-a; } ); // sort descending
//var toBeRankedSorted = toBeRanked.slice().sort( function( a,b ) { return a-b; } ); // sort ascending
var ranks = {}; // each value from the input array will become a key here and have a rank assigned
var ranksCount = {}; // each value from the input array will become a key here and will count number of same elements
// STEP 2
for (var i = 0; i < toBeRankedSorted.length; i++) { // here we populate ranks and ranksCount
var currentValue = toBeRankedSorted[ i ].toString();
if ( toBeRankedSorted[ i ] != toBeRankedSorted[ i-1 ] ) ranks[ currentValue ] = i; // if the current value is the same as the previous one, then do not overwrite the rank that was originally assigned (in this way each unique value will have the lowest rank)
if ( ranksCount[ currentValue ] == undefined ) ranksCount[ currentValue ] = 1; // if this is the first time we iterate this value, then set count to 1
else ranksCount[ currentValue ]++; // else increment by one
}
var ranked = [];
// STEP 3
for (var i = toBeRanked.length - 1; i >= 0; i--) { // we need to iterate backwards because ranksCount starts with maximum values and decreases
var currentValue = toBeRanked[i].toString();
ranksCount[ currentValue ]--;
if ( ranksCount[ currentValue ] < 0 ) { // a check just in case but in theory it should never fail
console.error( "Negative rank count has been found which means something went wrong :(" );
return false;
}
ranked[ i ] = ranks[ currentValue ]; // start with the lowest rank for that value...
ranked[ i ] += ranksCount[ currentValue ]; // ...and then add the remaining number of duplicate values
}
return ranked;}
I also needed to do something else for my script.
The above output has the following meaning:
index - the ID of the element in the input array
value - the rank of the element from the input array
And I needed to basically 'swap the index with the value', so that I have a list of element IDs, arranged in the order of their ranks:
function convertRanksToListOfElementIDs( ranked ) { // elements with lower ranks will be first in the list
var list = [];
for (var rank = 0; rank < ranked.length; rank++) { // for each rank...
var rankFound = false;
for (var elementID = 0; elementID < ranked.length; elementID++) { // ...iterate the array...
if ( ranked[ elementID ] == rank ) { // ...and find the rank
if ( rankFound ) console.error( "Duplicate ranks found, rank = " + rank + ", elementID = " + elementID );
list[ rank ] = elementID;
rankFound = true;
}
}
if ( !rankFound ) console.error( "No rank found in ranked, rank = " + rank );
}
return list;}
And some examples:
ToBeRanked:
[36, 33, 6, 26, 6, 9, 27, 26, 19, 9]
[12, 12, 19, 22, 13, 13, 7, 6, 13, 5]
[30, 23, 10, 26, 18, 17, 20, 23, 18, 10]
[7, 7, 7, 7, 7, 7, 7, 7, 7, 7]
[7, 7, 7, 7, 7, 2, 2, 2, 2, 2]
[2, 2, 2, 2, 2, 7, 7, 7, 7, 7]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
rankArrayElements( ToBeRanked ):
[0, 1, 8, 3, 9, 6, 2, 4, 5, 7]
[5, 6, 1, 0, 2, 3, 7, 8, 4, 9]
[0, 2, 8, 1, 5, 7, 4, 3, 6, 9]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
[5, 6, 7, 8, 9, 0, 1, 2, 3, 4]
[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
convertRanksToListOfElementIDs( rankArrayElements( ToBeRanked ) ):
[0, 1, 6, 3, 7, 8, 5, 9, 2, 4]
[3, 2, 4, 5, 8, 0, 1, 6, 7, 9]
[0, 3, 1, 7, 6, 4, 8, 5, 2, 9]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
[5, 6, 7, 8, 9, 0, 1, 2, 3, 4]
[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
function rank(arr) {
var ret = [];
var s = [];
var i = 0;
var _key_;
for (_key_ in arr) {
var v;
v = arr[_key_];
if (!s[v]) {
s[v] = ++i;
}
ret.push( {
'Mark': v,
'Rank': s[v]
});
}
return ret;
}
var marks = [
65,
41,
38,
38,
37,
37,
92,
84,
84,
84,
83
];
marks.sort(function(a, b) {
return b-a;
});
var rank = rank(marks);
console.log(rank);
Concise, efficient, flexible.
Items with same score have same ranks, yet the next different score get a rank shifted by n (based on index). Input must be a array sorted by values of the sourceColumn. Two versions of the code, pick the one you like :
for(){ } loop
array.map()
var studentsSortedByGrades = [
{ name: "A", grade: 5 },
{ name: "B", grade: 3 },
{ name: "C", grade: 3 },
{ name: "D", grade: 2 },
];
var addRankFORLOOP = function(sortedArr,sourceColumn,newColumn){
for(var i = 0; i<sortedArr.length; i++){ //
sortedArr[i][newColumn] =
i===0 || sortedArr[i][sourceColumn] !== sortedArr[i-1][sourceColumn] ? i+1 // anytime new grade appears, rank=i
: sortedArr[i-1][newColumn] // elseIf: equal grade, then equal rank
}
return sortedArr;
};
/*//OR
var addRankMAP = function(sortedArr,sourceColumn,newColumn){
return sortedArr.map((item,i) => {
item[newColumn] = i===0 || sortedArr[i][sourceColumn] !== sortedArr[i-1][sourceColumn] ? i+1 // anytime new grade appears, rank=i
: sortedArr[i-1][newColumn] // elseIf: equal grade, then equal rank
return item; })
}; /**/
var withRanks = addRankFORLOOP(studentsSortedByGrades,'grade','rank');
console.log(withRanks) // ranks: 1,2,2,4
Related
I am solving a problem which asks me to return the number with the highest frequency(mode). For example, if arr contains [3, 9, 3, 1, 6] the output should be 3. If there is more than one mode, I want to return the one that appeared first. [6, 6, 3, 3, 5, 5] should return 6 because it appeared first. If there is no mode, I want to return 0. The array will not be empty. I am new to algorithms, please suggest a simpler solution for me.
function Mode(arr) {
const arrayObject = {};
arr.forEach(arr => {
if(!arrayObject[arr]) {
arrayObject[arr] = 1
// console.log(arrayObject)
} else if(arrayObject[arr]){
arrayObject[arr] += 1
// console.log(arrayObject)
}
})
console.log(arrayObject) // { '3': 2, '5': 2, '6': 2 } array keys are automatically sorted in ascending other.This could be the problem but I don't know how to unsort the arrays//
let highestValueKey = 0;
let highestValue = 0
for(let key in arrayObject) {
const value = arrayObject[key]
if(value > highestValue) {
highestValue = value
highestValueKey = key
}
}
return Number(highestValueKey)
}
console.log(Mode([6, 6, 3, 3, 5, 5])) // 3 instead of 6
Just keep track of both count AND when it was first seen.
function mode (arr) {
const countSeen = {};
const firstSeen = {};
for (let i = 0; i < arr.length; i++) {
let elem = arr[i];
if (! countSeen[elem]) {
countSeen[elem] = 1;
firstSeen[elem] = i;
}
else {
countSeen[elem]++;
}
}
let mostSeenCount = 0;
let mostSeenValue = null;
for (let elem of Object.keys(countSeen)) {
if (mostSeenCount < countSeen[elem] ||
(mostSeenCount == countSeen[elem] && firstSeen[elem] < firstSeen[mostSeenValue])
) {
mostSeenCount = countSeen[elem];
mostSeenValue = elem;
}
}
return mostSeenValue;
}
console.log(mode([5, 6, 6, 6, 3, 3, 5, 5]))
You could use a Map whose keys are the array values, and the corresponding Map value is the frequency count:
Create the map and initialise the counts with 0
Increment the count as each input value is visited.
Use Math.max to get the greatest count from that map
Iterate the map to find the first count that matches that maximum
As Map entries are iterated in insertion order, the correct key will be identified in the last step.
function mode(arr) {
const counts = new Map(arr.map(i => [i, 0]));
for (const i of arr) counts.set(i, counts.get(i) + 1);
const maxCount = Math.max(...counts.values());
for (const [i, count] of counts) {
if (count == maxCount) return i;
}
}
console.log(mode([3, 9, 3, 1, 6])); // 3
console.log(mode([6, 6, 3, 3, 5, 5])); // 6
console.log(mode([3, 9, 3, 6, 1, 9, 9])); // 9
console.log(mode([5, 6, 6, 6, 3, 3, 5, 5])); // 5
You could use reduce to count the number of occurrences, then choose the max from there.
function mode(arr) {
const counts = arr.reduce((result, value, index) => {
// result is the object we're building up.
// value is the current item from the array.
// index is value's position within the array
// if result[value] doesn't already exist, create it
result[value] = (result[value] || { index, value, count: 0 });
// increment the 'count' for this value
result[value].count++;
// return the updated result
return result;
}, {});
// sort the entries by count in descending order, then by index
// ascending such that sorted[0] will be the entry with the highest
// count, and lowest index if more that one element has the same count
const sorted = Object.values(counts)
.sort((
{count: ca, index: ia},
{count: cz, index: iz}
) => (cz - ca) || (ia - iz));
// then return that entry's value
return sorted[0].value;
}
console.log(mode([6, 6, 3, 3, 5, 5])) // 6
console.log(mode([3, 9, 3, 1, 6])) // 3
console.log(mode([3, 9, 3, 6, 1, 9, 9])) // 9
I did this module on functions and execution context - all questions have gone well but there is one challenge I have spent a lot of time on and still can't figure it out. Any help will be greatly appreciated. Thank you
Challenge question says:
Write a function addingAllTheWeirdStuff which adds the sum of all the odd numbers in array2 to each element under 10 in array1.
Similarly, addingAllTheWeirdStuff should also add the sum of all the even numbers in array2 to those elements over 10 in array1.
BONUS: If any element in array2 is greater than 20, add 1 to every element in array1.
// Uncomment these to check your work!
// console.log(addingAllTheWeirdStuff([1, 3, 5, 17, 15], [1, 2, 3, 4, 5])); // expected log [10, 12, 14, 23, 21]
// console.log(addingAllTheWeirdStuff([1, 3, 5, 17, 15, 1], [1, 2, 3, 4, 5, 22])); // expected log [11, 13, 15, 46, 44, 11]
// my attempt so far:
function addingAllTheWeirdStuff(array1, array2) {
// ADD CODE HERE
let result = []
for (let i = 0; i < array2.length; i++) {
if (array2[i] > 20) {
result = array1[i] += 1
}
}
for (let i = 0; i < array2.length; i++) {
if (array2[i] % 2 === 0 && array1[i] > 10) {
result = array1[i] + array2[i]
}
}
for (let i = 0; i < array2.length; i++) {
if (array2[i] % 2 !== 0 && array1[i] < 10) {
result = array1[i] + array2[i]
}
}
return result
}
You can easily achieve this using reduce and map array method, with the ternary operator:
const array1 = [1, 3, 5, 17, 15];
const array2 = [1, 2, 3, 4, 5];
function addingAllTheWeirdStuff(array1, array2) {
const oddSum = array2.reduce((sum, current) => current % 2 ? current + sum : 0 + sum, 0)
const oddEven = array2.reduce((sum, current) => current % 2 == 0 ? current + sum : 0 + sum, 0)
return array1.map(num => num < 10 ? num + oddSum : num + oddEven)
}
console.log(addingAllTheWeirdStuff(array1, array2))
If you break the challenge into smaller pieces, you can deconstruct it better and come up with your solutions.
This is what I did... I will be adding more comments shortly with more explanations
I chose to keep using loops as I assumed this was the point of the challenges (to practice for loops, multiple conditions, etc) - In other words, I chose to not use map / reduce on purpose but if that's allowed, use the answer by #charmful0x as it results in less code :)
// function to get sum of all odd numbers in array
function getSumOfAllOddNumbersInArray( elementArray ){
var sumOfOddNumbers = 0;
for (let i = 0; i < elementArray.length; i++) {
// use remainder operator to find out if element is odd or not
if (elementArray[i] % 2 !== 0 ) {
sumOfOddNumbers += elementArray[i];
}
}
return sumOfOddNumbers;
}
// function to get sum of all EVEN numbers in array
function getSumOfAllEvenNumbersInArray( elementArray ){
var sumOfEvenNumbers = 0;
for (let i = 0; i < elementArray.length; i++) {
// use remainder operator to find out if element is odd or not
if (elementArray[i] % 2 === 0 ) {
sumOfEvenNumbers += elementArray[i];
}
}
return sumOfEvenNumbers;
}
// Return true if there is at least one element in array that is greater than 20
function hasElementOverTwenty( elementArray ){
for (let i = 0; i < elementArray.length; i++) {
if (elementArray[i] > 20 ) {
// no need to keep looping, we found one - exit function
return true;
}
}
return false;
}
function addingAllTheWeirdStuff( firstArray, secondArray ){
var sumOfOddNumbersInArray = getSumOfAllOddNumbersInArray( secondArray );
var sumOfEvenNumbersInArray = getSumOfAllEvenNumbersInArray( secondArray );
var needToAddOne = hasElementOverTwenty( secondArray );
for (let i = 0; i < firstArray.length; i++) {
// Challenge One
if (firstArray[i] < 10) {
firstArray[i] = firstArray[i] + sumOfOddNumbersInArray;
} else if (firstArray[i] > 10) {
// Challenge Two
firstArray[i] = firstArray[i] + sumOfEvenNumbersInArray;
}
// bonus
if( needToAddOne ){
firstArray[i]++;
}
}
return firstArray;
}
// Uncomment these to check your work!
console.log(addingAllTheWeirdStuff([1, 3, 5, 17, 15], [1, 2, 3, 4, 5]));
console.log('expected:' + [10, 12, 14, 23, 21] );
console.log(addingAllTheWeirdStuff([1, 3, 5, 17, 15, 1], [1, 2, 3, 4, 5, 22]));
console.log('expected:' + [11, 13, 15, 46, 44, 11] );
Challenge question says: Write a function addingAllTheWeirdStuff which adds the sum of all the odd numbers in array2 to each element under 10 in array1.
Similarly, addingAllTheWeirdStuff should also add the sum of all the even numbers in array2 to those elements over 10 in array1.
BONUS: If any element in array2 is greater than 20, add 1 to every element in array1.
It is for a studying purpose. Have a big array of integers need to return an array that has 1 added to the value represented by the array.
Tried to convert the array into an integer, but after using
parseInt('9223372036854775807', 10) received 9223372036854776000, instead of 9223372036854775807
What is going wrong here?
var arr = [ 9, 2, 2, 3, 3, 7, 2, 0, 3, 6, 8, 5, 4, 7, 7, 5, 8, 0, 7 ];
function upArray(arr){
var numb = arr.join('');
numb = parseInt(numb, 10);
var result = numb + 1;
console.log(result);
result = result.toString(10).split('').map(Number);
return result;
}
You are exceeding the capacity of JavaScript's number type
IEEE-754 double-precision floating point (the kind of number JavaScript uses) can't precisely represent all numbers
Beyond Number.MAX_SAFE_INTEGER + 1 (9007199254740992), the IEEE-754 floating-point format can no longer represent every consecutive integer
also you dont need to use a second argument to parseInt unless you are looking to use a different base than decimal
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/parseInt
If you use the code with an array of numbers that when joined is within this limit your code will work
var arr = [ 9, 2, 2, 3, 3, 7, 2, 0, 3, 6, 8, 5 ];
function upArray(arr){
var numb = arr.join('');
numb = parseInt(numb);
var result = numb + 1;
console.log(result)
result = result.toString(10).split('').map(Number);
return result;
}
console.log(upArray(arr))
As you're exceeding the MAX_SAFE_INTEGER.
If you just want to display you can go this way
var arr = [ 9, 2, 2, 3, 3, 7, 2, 0, 3, 6, 8, 5, 4, 7, 7, 5, 8, 0, 7 ];
function addone(arr){
let carry = 0;
for(let i=arr.length-1; i>=0; i--){
if(i === arr.length-1) {
if( arr[i]+1 > 9){
arr[i] = 10-(arr[i] + 1);
carry = 1;
} else {
arr[i] +=1;
carry= 0;
}
}
if( i !== arr.length-1 ){
if( carry === 0) break;
if( arr[i]+1+carry > 9){
arr[i] = 10-(arr[i] + carry);
carry = 1;
} else {
arr[i] +=carry;
carry= 0;
}
}
}
if(carry === 1)
arr.unshift(1)
return arr;
}
console.log(addone(arr).join(''))
console.log(addone([1,2,9]).join(''))
console.log(addone([9,9,9]).join(''))
The value is going beyond the max number value.
Here is recursive appproch for the problem:
function upArray(arr, lastIndex){
if(lastIndex == undefined){
lastIndex = arr.length - 1;
}
if(lastIndex < 0){
return;
}
if(arr[lastIndex] == 9){
arr[lastIndex] = 0;
upArray(arr, lastIndex - 1);
}
else {
arr[lastIndex] = arr[lastIndex] + 1;
}
return arr;
}
var arr = [ 9, 2, 2, 3, 3, 7, 2, 0, 3, 6, 8, 5, 4, 7, 7, 5, 8, 0, 9];
var result = upArray(arr);
console.log(result);
Another solution so you can choice =)
var arr = [9,9,9];//[ 9, 2, 2, 3, 3, 7, 2, 0, 3, 6, 8, 5, 4, 7, 7, 5, 8, 0, 7 ];
var i = arr.length;
var append = true;
while(append){
if(--i < 0){
arr.unshift(1);
break;
}
var v = arr[i];
if(++v >= 10)
v -= 10;
else
append = false;
arr[i] = v;
}
var r = arr.join('');
console.log(r);
it means the maximum range for an Intiger number has reached, here is a link
https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Number/MAX_SAFE_INTEGER
to solve this split the array value and add one to it and then combine then back and display the entire array as a String (don't parse it).
function upArray(arr){
var temp = arr;
var len = arr.length;
var temp2 = arr;
temp2 = temp2.slice(0,len/2).join('');
temp2 = parseInt(temp2);
temp = temp.slice(len/2).join('');
numb = parseInt(temp) +1;
if(numb.toString().length > (len/2 + len%2))
{
numb = numb.toString().slice(1);
temp2++;
}
var result = temp2.toString() + numb.toString();
console.log(result);
result = result.split('').map(Number);
return result;
}
hope it helps and have pass through every test...
As everybody would agree that the issue here is having a value that is exceeding the capacity of JavaScript's number type, we can expect that there'll be proposed workarounds like having to split the array into multiple array and work from there.
We can actually solve this on another approach. Since your representation of a number is splitting it into single digits stored as an array, and you want to perform a simple addition on it, we can observe a representation of a simple/elementary addition. The one where we add a value digit by digit from the bottom and make use of the "Carry Over" concept. We can actually do it that way.
It will look somewhat like this (A bit longer code for readability):
var x = [1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 2, 3, 4, 5, 6, 7, 8, 9];
var y = [9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9];
var add1 = (arr) => {
var hasCarryOver = true;
for (var index = arr.length - 1; index >= 0; index--) {
if (!hasCarryOver) {
break;
}
if (arr[index] < 9) {
arr[index] = arr[index] + 1;
hasCarryOver = false;
} else {
arr[index] = 0;
}
}
if (hasCarryOver) {
arr.unshift(1);
}
return arr;
};
x = add1(x);
y = add1(y);
console.log('result x add 1', x);
// [1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 2, 3, 4, 5, 6, 7, 9, 0]
console.log('result y add 1', y);
// [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
I have array:
arr = [1,2,3,4,5,6,7,8,9,10,11,12,13,14];
Then I want to make group of 4 elements.
Every iteration, this array must be modified until it get's final face.
Step 1:
arr = [[1,2,3,4],5,6,7,8,9,10,11,12,13,14];
Step 2:
arr = [[1,2,3,4],[5,6,7,8],9,10,11,12,13,14];
Step 3:
arr = [[1,2,3,4],[5,6,7,8],[9,10,11,12],13,14];
Step 3:
arr = [[1,2,3,4],[5,6,7,8],[9,10,11,12],[13,14]];
How is this possible?
I tried this:
var array = [1,2,3,4,5,6,7,8,9,10,11,12,13,14]
var i,j,temparray,chunk = 4;
for (i=0,j=array.length; i<j; i+=chunk) {
temparray = array.slice(i,i+chunk);
console.log(temparray);
}
But I don't know then how to save this chunk into own array and not in the new array.
Using Array#reduce method.
const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14],
newArr = arr.reduce((acc, item, index) => {
if ((index) % 4 === 0) {
acc.push([item]);
} else {
acc[acc.length - 1].push(item);
}
return acc;
}, []);
console.log(newArr); // [ [ 1, 2, 3, 4 ], [ 5, 6, 7, 8 ], [ 9, 10, 11, 12 ], [ 13, 14 ] ]
You could splice the array until the length is smaller than the index of the last insertation.
var array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14],
i = 0;
while (i < array.length) {
array.splice(i, 0, array.splice(i, 4));
console.log(JSON.stringify(array));
i++;
}
lodash probably has better performances than my implementation, but if you are looking to do so with vanilla javascript then you can like this (though many other ways are possible):
var arr = [1,2,3,4,5,6,7,8,9,10,11,12,13,14];
var newArr = arr.reduce((acc, val, idx)=>{
if(idx % 4 === 0){
acc.push([]);
}
acc[acc.length-1].push(val)
return acc
}, [])
console.log(newArr);
The lodash method chunk will do this for you.
result = _.chunk(arr, 4);
function chunkArray(myArray, chunk_size){
var index = 0;
var arrayLength = myArray.length;
var tempArray = [];
for (index = 0; index < arrayLength; index += chunk_size) {
myChunk = myArray.slice(index, index+chunk_size);
// Do something if you want with the group
tempArray.push(myChunk);
}
return tempArray;
}
// Split in group of 3 items
var result = chunkArray([1,2,3,4,5,6,7,8], 3);
// Outputs : [ [1,2,3] , [4,5,6] ,[7,8] ]
console.log(result);
Just push it to the resulting array:
const chunk = 4, result = []
for (var i = 0, j = array.length; i < j; i += chunk) {
result.push(array.slice(i,i + chunk));
}
I thought it would be fun too if I add one more solution using recursive calls, Happy coding!
Test it here
function split(arr, offset, res){
//stop condition (offset exceeds len of array)
if(offset>arr.length)
return res;
//slice 4 elms
res.push(arr.slice(offset,offset+4));
//recursion
return split(arr, offset+4, res);
}
var res = split([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14], 0, []);
console.log(res);
Okay, I've only figured out how to get one mode out of the array..
But I want to get 2, 3 or more if they occur the same amount of times.
This is the code:
var frequency = {}; // array of frequency.
var maxFreq = 0; // holds the max frequency.
for (var i in array) {
frequency[array[i]] = (frequency[array[i]] || 0) + 1; // increment frequency.
if (frequency[array[i]] > maxFreq) { // is this frequency > max so far ?
maxFreq = frequency[array[i]]; // update max.
mode = array[i]; // update result.
}
}
So right now, if I've got a array = [3, 8, 3, 6, 1, 2, 9];
I get mode = 3;
But what I'm looking for is if array = [3, 6, 1, 9, 2, 3, 6, 6, 3, 1, -8, 7];
I want to get the mode = 3, 6;
The question doesn't state how to get the modes, but if we want them in an array, we could change the code like this:
function getModes(array) {
var frequency = []; // array of frequency.
var maxFreq = 0; // holds the max frequency.
var modes = [];
for (var i in array) {
frequency[array[i]] = (frequency[array[i]] || 0) + 1; // increment frequency.
if (frequency[array[i]] > maxFreq) { // is this frequency > max so far ?
maxFreq = frequency[array[i]]; // update max.
}
}
for (var k in frequency) {
if (frequency[k] == maxFreq) {
modes.push(k);
}
}
return modes;
}
alert(getModes([3, 6, 1, 9, 2, 3, 6, 6, 3, 1, -8, 7]));
function modeCount(data) {
let modecount = [];
let valueArr = [];
let dataSet = new Set(data);
for (const iterator of dataSet) {
const filteredNum = data.filter((num) => iterator === num);
modecount.push({
mode: iterator,
count: filteredNum.length
});
}
modecount.sort((a, b) => {
return b.count - a.count;
});
modecount.forEach(value => {
if (value.count === modecount[0].count) {
valueArr.push(value.mode);
}
});
return valueArr;
}
let ages = [3, 6, 1, 9, 2, 3, 6, 6, 3, 1, -8, 7]
console.log(modeCount(ages));