I have an object list to store indexes just like that:
const initialIndexes = {
0: [0,1,2],
1: [0,1]
}
At this point I have a highlightedResultIndex variable. It gives an index like this:
highlightedResultIndex = 0 - case 1
highlightedResultIndex = 4 - case 2
highlightedResultIndex = 2 - case 3
...
And I finally try to get the following results by highlightedResultIndex
For the case 1:
result = {
0: 0, // index from initialIndexes
1: -1
}
For the case 2:
result = {
0: -1,
1: 1 // index from initialIndexes
}
For the case 3:
result = {
0: 2 // index from initialIndexes
1: -1
}
Maybe there is an easy method or there may be a certain algorithm for this, but I didn't know how to research it so I wanted to write it here. I would be glad if you help.
EDIT:
Let me put here some of examples
// This is data from the server side.
const initialIndexes = {
0: [0,1,2,3],
1: [0,1,2],
2: [0,1,2],
3: [0,1,2,3,4]
}
// So, I need to index object like this by highlightedResultIndex variable
// highlightedResultIndex = 0
{
0:0,
1:-1,
2:-1,
3:-1
}
// highlightedResultIndex = 6
{
0: -1,
1:2,
2:-1,
3:-1
}
// highlightedResultIndex = 10
{
0: -1,
1:-1,
2:-1,
3:0
}
You could take the wanted index value and reduce it by the lenght of the arrays until it fits into an array.
const
initialIndexes = { 0: [0, 1, 2, 3], 1: [0, 1, 2], 2: [0, 1, 2], 3: [0, 1, 2, 3, 4] },
getIndices = n => Object.fromEntries(Object
.entries(initialIndexes)
.map(([key, array]) => {
const value = n >= 0 && n < array.length
? array[n] // or just n
: -1;
n -= array.length;
return [key, value];
})
);
console.log(getIndices(0)); // { 0: 0, 1: -1, 2: -1, 3: -1 }
console.log(getIndices(6)); // { 0: -1, 1: 2, 2: -1, 3: -1 }
console.log(getIndices(10)); // { 0: -1, 1: -1, 2: -1, 3: 0 }
.as-console-wrapper { max-height: 100% !important; top: 0; }
Related
If I remove the element from the array and add it to the Hash Table as shown below. Can we say the function adds no extra space. (overall constant extra space).
const myFunc = (arr) => {
const len = arr.length - 1;
const hTable = {};
for (let i = len; i >= 0; i--) {
hTable[arr.pop()] = true;
}
return hTable; // {1: true, 2: true, 3: true, 4: true, 5: true, 6: true, 8: true, 10: true}
// return arr; // []
};
myFunc([2, 4, 3, 6, 8, 10, 5, 1]);
Extra space, I mean complexity. The complexity to consider >= O(log n)
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 want to reduce duplication in my JavaScript syntax.
No matter how much I think about it, it doesn't come to mind.
It doesn't matter if it is for loop or any syntax!
i add some of case and result
if if it is correct answer would be result
// case 1
// const max = [1, 31, 0, 0]
// const min = [1, 31];
// result = [3, 5]
// case 2
// const max = [0, 0, 0, 0, 0, 0]
// const min = [0, 0]
// result = [1, 6]
// case 3
// const max = [45, 4, 35, 20, 3, 9]
// const min = [45, 4, 35, 20, 3, 9]
// result = [1, 1]
if (max.length === 6) {
answer[0] = 1;
} else if (max.length === 5) {
answer[0] = 2;
} else if (max.length === 4) {
answer[0] = 3;
} else if (max.length === 3) {
answer[0] = 4;
} else if (max.length === 2) {
answer[0] = 5;
} else {
answer[0] = 6;
}
if (min.length === 6) {
answer[1] = 1;
} else if (min.length === 5) {
answer[1] = 2;
} else if (min.length === 4) {
answer[1] = 3;
} else if (min.length === 3) {
answer[1] = 4;
} else if (min.length === 2) {
answer[1] = 5;
} else {
answer[1] = 6;
}
is max and min length between 1 and 6? because judging your code, it looks like it.
answer[0] = 7 - max.length
sure looks a bit neater, at the least you could eliminate many if blocks and leave the else block in case max.length is not an integer between 1 and 6
//pseudocode
if( max.length between 1 and 6 inclusive) {
answer[0] = 7- max.length
} else {
answer[0] = some default value, 6?
}
the 7 looks like a magic number, but with more context, you can name it something better
const getAnswers = x => (x < 1 || x > 6) ? 6 : 7 - x;
// case 1
let max = [1, 31, 0, 0]
let min = [1, 31];
// result = [3, 5]
let answer = [getAnswers(max.length), getAnswers(min.length)];
console.log('max.length: ', max.length, ' min.length: ', min.length, ' answer array: ', answer);
// case 2
max = [0, 0, 0, 0, 0, 0]
min = [0]
// result = [1, 6]
answer = [getAnswers(max.length), getAnswers(min.length)];
console.log('max.length: ', max.length, ' min.length: ', min.length, ' answer array: ', answer);
// case 3
max = [45, 4, 35, 20, 3, 9]
min = [45, 4, 35, 20, 3, 9]
// result = [1, 1]
answer = [getAnswers(max.length), getAnswers(min.length)];
console.log('max.length: ', max.length, ' min.length: ', min.length, ' answer array: ', answer);
By reducing duplication, do you mean you want to decrease the length of your code or increase readability?
If you want to increase readability, some people prefer select/case than if/elseif:
switch(max.length) {
case 6:
answer[0] = 1;
break;
case 5:
answer[0] = 2;
break;
case 4:
answer[0] = 3;
break;
case 3:
answer[0] = 4;
break;
case 2:
answer[0] = 5;
break;
default:
answer[0] = 6;
}
If you want to reduce length, you can just do something like #Bergi said in comment:
answer = [7-max.length, 7-min.length];
But if max and min variable is from user input or from external source, unexpected thing may occurs:
max = {length: -5};
min = {length: -99};
answer = [7-max.length, 7-min.length];
console.log(answer)
// outputs [12,106]
The code may outputs a number outside 1-6 integer range.
So you should also add some Math.max and Math.min if you want your code to behave exactly like your if-elseif statement:
max = {length: -5};
min = {length: -99};
answer = [
Math.max(Math.min(7-max.length,1),6),
Math.max(Math.min(7-min.length,1),6)
];
console.log(answer)
// outputs [6,6]
Of course if you take input from external source you should sanitize/validate it first, but if it's an overkill, you can also use the above Math.min and Math.max function
you need to write just these two lines instead :)
answer[0] = 7 - max.length
answer[1] = 7 - min.length
Im learning JS and have set myself the challenge to re-create a football league table, from an array of match results.
Everything is going really well and I'm almost complete, but I can't filter my 'FORM GUIDE' array to their corresponding Letters.
I have the points scored over the last 5 games ONLY outputted as an array (below);
[3, 1, 3, 0, 3]
But I'd like to output this as 3 = W, 1 = D, 0 = L.
So...
W, D, W, L, W
Can someone please explain how I can do this?
Thank you
'use strict';
// Tottenham's Premier League scores & points 21-22 //
//--------------------------------------------------//
const scoresPoints = [
[1, 0, 3], // Watford
[1, 1, 1], // Southampton
[3, 0, 3], // Crystal Palace
[2, 2, 1], // Liverpool
[3, 0, 3], // Norwich
[2, 0, 3], // Brentford
[2, 1, 3], // Leeds
[0, 0, 1], // Everton
[3, 2, 3], // Newcastle
[0, 3, 0], // Man U
[0, 1, 0], // West Ham
[2, 1, 3], // Villa
[1, 3, 0], // Arsenal
[0, 3, 0], // Chelsea
[0, 3, 0], // Crystal Palace
[1, 0, 3], // Watford
[1, 0, 3], // Wolves
[1, 0, 3], // Man City
];
// Define The functions & arrays--------------------//
//--------------------------------------------------//
let tottenhamScores;
let totalTottenhamGoals;
let totalTottenhamPoints;
let totalOpponentsGoals;
let tottenhamForm = [];
// The goals scored by Tottenham
const tottenhamGoals = [];
// The points scored by Tottenham
const tottenhamPoints = [];
// The goals scored by the opponents
const opponentsGoals = [];
// Filter the data from each array------------------//
//--------------------------------------------------//
for (let i = 0; i < scoresPoints.length; i++) {
tottenhamScores = scoresPoints[i][0];
// Just Tottenham's goals
tottenhamGoals.push(tottenhamScores);
// Just Tottenham's points
const leaguePoints = scoresPoints[i][2];
tottenhamPoints.push(leaguePoints);
// Just the opponents goals
const opponentsScores = scoresPoints[i][1];
opponentsGoals.push(opponentsScores);
// Just Tottenham's Form
const leagueForm = scoresPoints[i][2];
tottenhamForm.push(leagueForm);
}
// Adding up the arrays-----------------------------//
//--------------------------------------------------//
// Adding up Tottenham's goals
for (let i = 0; i < tottenhamGoals.length; i++) {
totalTottenhamGoals = tottenhamGoals.reduce(function (a, b) {
return a + b;
}, 0);
}
// Adding up Tottenham's points
for (let i = 0; i < tottenhamPoints.length; i++) {
totalTottenhamPoints = tottenhamPoints.reduce(function (a, b) {
return a + b;
}, 0);
}
// Adding up the opponents goals
for (let i = 0; i < opponentsGoals.length; i++) {
totalOpponentsGoals = opponentsGoals.reduce(function (a, b) {
return a + b;
}, 0);
}
// Last 5 games-------------------------------------//
//--------------------------------------------------//
// Find the individual values
function occurrence(pointValues, value) {
return pointValues.filter(v => v === value).length;
}
const win = occurrence(tottenhamPoints, 3);
const draw = occurrence(tottenhamPoints, 1);
const loss = occurrence(tottenhamPoints, 0);
// Filter to last five games
function lastFiveGames(form, five) {
form = tottenhamForm.slice(0, five);
return form;
}
const latestForm = lastFiveGames(tottenhamForm, 5);
// Convert points to represented letters
const letteredResult = latestForm.map(result => {
switch (result) {
case 0:
return 'L';
case 1:
return 'D';
case 3:
return 'W';
default:
return 'No Form To Display';
}
});
// Print the statement & table----------------------//
//--------------------------------------------------//
console.log(
`SUMMARY
--------
--------
Throughout the 2021-22 Premier League season, Tottenham Hotspur have scorred ${totalTottenhamGoals} goals and conceeded ${totalOpponentsGoals}.
This has gained Tottenham Hotspur ${totalTottenhamPoints} points to date.
(Dropping ${
scoresPoints.length * 3 - totalTottenhamPoints
} points throughout the season from the maximum of ${
scoresPoints.length * 3
} available).
TABLE & FORM GUIDE ---
----------------------
${scoresPoints.length} Played
${win} Wins
${draw} Draws
${loss} Losses
${totalTottenhamGoals} For
${totalOpponentsGoals} Against
${totalTottenhamGoals - totalOpponentsGoals} Goal Difference
${totalTottenhamPoints} POINTS IN TOTAL
FORM (Last 5 Games) ${letteredResult}
----------------------
----------------------`
);
You can achieve this with Array.map and a nice switch statement. Try this way:
const arr = [3, 1, 3, 0, 3]
const matched = arr.map(result => {
switch(result){
case 0:
return 'L'
case 1:
return 'D'
case 3:
return 'W'
default:
return 'X'
}
})
console.log(matched)
You can use map:
[3, 1, 3, 0, 3].map(e => { if (e == 3) return "W"; if (e == 1) return "D"; if (e == 0) return "L"; throw `Unexpected value: ${e}`; })
let arr = [3, 1, 3, 0, 3];
let arrMap = arr.map((i) => {
if (i == 3) return "W";
if (i == 0) return "L";
return "D"
})
console.log(arrMap)
You can achieve this clean and simple using map and an object acting as Enum where the key will represent the points and the value will represent the result char.
const array = [3, 1, 3, 0, 3];
const cases = {0: 'L', 1: 'D', 3: 'W'};
const matches = array.map(e => cases[e]);
console.log(matches)
More about map - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map
Instead of using map, you could also use forEach. The main difference is that map will return a new array, whereas forEach doesn't return anything and can be used to change the original array. Here is how:
const logic = {
3: 'W',
1: 'D',
0: 'L'
}
const data = [3, 1, 3, 0, 3];
data.forEach((value, key) => data[key] = logic[value]);
console.log(data);
const arr = [3, 1, 3, 0, 3, 2, 4];
const data = arr.map(v => ['L','D','_','W'][v] || '_');
console.log( data );
Write a function - countNumbers It should accept string with different symbols and return an object which contains counts of each number.
Tip: consider reusing makeNumber function.
My solution is not full, what should i do the next?
function countNumbers (string) {
let numbers = [];
for (let i = 0; i < string.length; i++) {
if (!isNaN(parseInt(string[i]))){
numbers.push([string[i]])
}
}
return numbers.join('');
};
for example: countNumbers('erer384jj4444666888jfd123');
// => {'1': 1, '2': 1, '3': 2, '4': 5, '6': 3, '8': 4}
countNumbers('jdjjka000466588kkkfs662555');
// => {'0': 3, '2': 1, '4': 1, '5': 4, '6': 4, '8': 2}
You can use an object instead of an array, and check if the property already exists. If it does then add 1, else set it to start with 1.
In your code you return a string with return numbers.join(''); but in this case your can return the object instead.
function countNumbers(string) {
let numbers = {};
for (let i = 0; i < string.length; i++) {
let val = string[i];
if (!isNaN(parseInt(val))) {
val in numbers ? numbers[val]++ : numbers[val] = 1;
}
}
return numbers;
}
console.log(countNumbers('erer384jj4444666888jfd123'));
console.log(countNumbers('jdjjka000466588kkkfs662555'));
Or as pointed out by #secan as an alternative solution you can use a pattern [0-9] with the global flag /g to get the digits from the string.
const countNumbers = str => {
const counterObj = {};
str.match(/[0-9]/g).forEach(
s => counterObj.hasOwnProperty(s) ? counterObj[s] += 1 : counterObj[s] = 1
);
return counterObj;
}
console.log(countNumbers('erer384jj4444666888jfd123'));
console.log(countNumbers('jdjjka000466588kkkfs662555'));