I'm currently still learning the basic JS and wondering how to answer this array type of question.
Question :
Given the participant's score sheet for your University Sports Day, You are required to find the runner-up score. You are given N scores. Store them in a list and find the score of the runner-up.
Input Format :
The first line contains N. The second line contains an array A[] of N integers each separated by a space.
Sample Input: [5,2,3,6,6,5]
Output Format :
Print the runner-up score.
Sample Output: 5
This is my code :
function uniqueScore (value, index, self) {
return self.indexOf(value) === index
}
var score = [5,2,3,6,6,5]
var filter = score.filter(uniqueScore)
var descSort = filter.sort().reverse()
function runnerUpScore(x) {
var runnerUp = descSort
return runnerUp
}
console.log(runnerUpScore(x))
The condition is I'm stuck when already sorting the array and removing duplicate. Hence, I need some guidance how to call the sorted array and only showing the index 1 from array list to show the runner up score.
The problem with your approach is you are sorting the array and then reversing it which costs lots of computation. Here is a simple solution in O(n). It iterates the array only once and finds the second-largest score, which is the runner-up score.
var scores = [1,2,3,4,5];
const runnerUpScore = (scores) => {
scores = [... new Set(scores)] // get unique elements
var largest = -1;
var secondLargest = -1;
scores.forEach((score) => {
if(score >= largest) {
secondLargest = largest;
largest = score;
} else if (score > secondLargest) {
secondLargest = score;
}
});
return secondLargest;
}
console.log(runnerUpScore(scores));
.sort() reverse:
let scores = [5, 2, 3, 6, 6, 5];
let reverseOrder = scores.sort((a, b) => b - a);
// [6, 6, 5, 5, 3, 2]
Filter out duplicates by converting array into a Set() then back to an array:
let set = new Set(reverseOrder)
// {6:6, 5:5, 3:3, 2:2} this is a representation there's much more to a Set.
let unique = [...set]
// [6, 5, 3, 2]
Get the score in the second index position:
unique[1]
// 5
const scores = [5, 2, 3, 6, 6, 5];
const reverseOrderUnique = [...new Set(scores.sort((a, b) => b - a))];
console.log(reverseOrderUnique);
console.log('Runner Up: '+reverseOrderUnique[1]);
You can simply achieve it by sort the array in descending order by using Array.sort() and filtered out the duplicates by using Set() method and then access the runner-up score from 1st index of the array.
Live Demo :
// Input array
const scores = [5,2,3,6,6,5];
// Sort the array in descending order and remove the duplicates by using Set() method.
const sortedScores = [...new Set(scores.sort((a,b) => b-a))];
// Runner Up score by accesing the 1st index value.
console.log(sortedScores[1]);
Related
Is it possible to use reduce to find the second largest element in an array? Without using sort methods. Something like this:
Obs: The code below is for finding the largest value. I need to find the second largest value and would like to use reduce(). Without using the sort methods
array1 = [12, 16, 1, 5]
array2 = [8, 4, 5, 6];
function largestElement(array){
largestE = array.reduce((acc,currentValue) => currentValue > acc ? currentValue : acc )
return largestE
}
console.log(largestElement(array1))
console.log(largestElement(array2))
WITHOUT DOING THIS:
function secondLargest(array){
array.sort((a,b) => a-b)
return array[array.length-2]
}
Yes there are several ways you can do this. Here is one solution:
const array1 = [5, 5, 1, 1, 2, 3, 4];
const array2 = [12,16,1,5];
const reducer = (accumulator, currentValue, idx, a) => {
let larger = a.filter(n=>n>currentValue) // Fetch larger values than n
.filter((n,i,a) => a.indexOf(n) === i); // Get Unique values
if(larger.length === 1){
// if there is only one unique value larger than n, n is your answer.
return accumulator = currentValue;
} else {
return accumulator = accumulator; // else preserve the accumulator value
}
}
console.log(array1.reduce(reducer));
console.log(array2.reduce(reducer));
I think that the simpler the better,
I will just create two variables and compare each element of the array
First make two variables outside the loop
inside the loop just ask if current number is bigger than larger
if its bigger then assign the value to largest and make the secondLargest with the values of largest
2)if it is not larger than largest but it is smaller than secondLargest than pass that numbe to the secondLargest, please see the code below
function FindSecondLargest() {
largest = 0
secondLargest =0
for (let i =0 i<array.length, i++)
{
if(array[i] >largest)
{
secondLargest = largest
largest=array[i]
}else if(array[i] <secondLargest){
secondLargest=array[i]
}
}
return secondLargest;
}
I'm looking to answer a coding challenge in JavaScript that I'm stuck on, here's the question:
Write a function which accepts an array of integers and returns an element of that array.
The function should determine the frequency of each element (how many times the element appears in the array) and whenever possible should return the element with the second-lowest frequency. Otherwise it should return the integer with the lowest frequency.
If there is more than one element satisfying the requirements then the second smallest one (according to value) should be returned.
Example outputs:
secondLowest( [4, 3, 1, 1, 2] ) === 1
secondLowest( [4, 3, 1, 1, 2, 2] ) === 2
secondLowest( [4, 3, 1, 2] ) === 2
This is what I've got so far although don't know how best to go about answering it after this:
function mode(array) {
if (array.length == 0) return null;
let modeMap = {};
let maxEl = array[0],
maxCount = 1;
for (let i = 0; i < array.length; i++) {
var el = array[i];
if (modeMap[el] == null) modeMap[el] = 1;
else modeMap[el]++;
if (modeMap[el] > maxCount) {
maxEl = el;
maxCount = modeMap[el];
}
}
return maxEl;
}
I was determined to give a generic, parameterized function, where no number is hardcoded.
Your example involved two hardcoded values:
The second least frequency should be selected
In cases of ties, the second least value should be selected
The following code works like this:
Get the frequency of each input value
Group together all values with the same frequency.
Sort these grouped pairs by frequency and select the nth-lowest (in your case, n=2)
If the nth-lowest frequency has multiple pairs, sort these pairs by value, and select the mth-lowest pair (in your case, m=2)
Return the value of this final pair
The m and n parameters I refer to here are called freqInd and valInd in the code. Note that in order to select the second-lowest frequency, freqInd should be 1, not 2 (since 0 would select the lowest, and therefore 1 selects the second-lowest).
let lowestFreqVal = (freqInd, valInd, values) => {
// Calculate frequencies in a map
let f = new Map();
for (let v of values) f.set(v, (f.get(v) || 0) + 1);
// Group together all val/freq pairs with the same frequency
let ff = new Map();
for (let [ val, freq ] of f) ff.set(freq, (ff.get(freq) || []).concat([ val ]));
// Sort these groups by frequency
let byFreq = [ ...ff ].sort(([ freq1 ], [ freq2 ]) => freq1 - freq2);
// Here are all the items of the `freqInd`-th lowest frequency, sorted by value
// Note that `[1]` returns an array of integers at the frequency, whereas `[0]` would return the frequency itself
let lowestItems = byFreq[ Math.min(byFreq.length - 1, freqInd) ][1]
.sort((v1, v2) => v1 - v2);
// Return the `valInd`-th lowest value
return lowestItems[ Math.min(lowestItems.length - 1, valInd) ];
};
console.log('Some random examples:');
for (let i = 0; i < 10; i++) {
// An array of random length, full of random integers
let arr = [ ...new Array(3 + Math.floor(Math.random() * 5)) ]
.map(v => Math.floor(Math.random() * 4));
// Show the result of `lowestFreqVal` on this random Array
console.log(`lowestFreqVal(1, 1, ${JSON.stringify(arr)}) = ${lowestFreqVal(1, 1, arr)}`);
}
This is not an optimal solution, since it resorts to using sort. It's known that the problem of finding some nth-maximal value in a list can be implemented to have a better runtime than sort (and a significantly better runtime when n is a small value - we can see this intuitively because if n=0, a single pass (O(n)) does the trick).
I have a problem with javascript arrays I am not sure how to approach.
First of all I want the second array's first value to be the same as the first value in the first array, and then add on to that.
I have an array and I want to add two values in the first array and push the result in to the second array, I then want to get the third value in the first array and add it to the last value in the second array, and then the fourth and fifth etc...
Example below because i'm finding it hard to explain!
var arr = [1, 2, 3, 4, 5];
var newArr = [];
End result of the second array (it's the result of adding consecutive values of the first array to the last value of the second array:
var newArr = [1, 3, 6, 10, 15];
I hope this makes sense - I'm finding it hard to think clearly about it!
This is a great candidate for reduce - you initialize you accumulator array with the first element of arr, and then you build your accumulator array as you iterate through the rest of the elements of arr:
var arr = [1, 2, 3, 4, 5];
var newArr = arr.reduce((acc, current) => {
acc.push((acc[acc.length - 1] || 0) + current);
return acc;
}, []);
console.log(newArr);
You can probably do it a smarter way using map/reduce or lodash, but the simplest option is a simple for loop:
var arr = [1, 2, 3, 4, 5];
var newArr = [];
for(let i = 0; i < arr.length; i++ ) { // iterate over input array
let incrementer = arr[i] // get value from input array
if( newArr[ newArr.length - 1 ] ) { // if the output array has a last value
incrementer += newArr[ newArr.length - 1 ] // add the last value
}
newArr.push(incrementer) // append the new value to end of output array
}
console.log(newArr)
I have my array=[5,4,3,1] below, I want to .push(2), then .sort() my array and find out the new number's location in the array that I just pushed. I know the answer the new number's location is in array[1].
var array = [5,4,3,1];
array.push(2); //My new number
var sortedArray = arr.sort();
// sortedArray [1,2,3,4,5]
// The new number's position went to array[1]
Is there any method to find out which position my new number went to?
You could sort an array with indices and take the store index for serarching the inde fo the sorted array.
var array = [5, 4, 3, 1],
index = array.push(2) - 1,
indices = array
.map((_, i) => i)
.sort((a, b) => array[a] - array[b]);
console.log(index); // old index
console.log(indices.indexOf(index)); // new index
console.log(indices);
You can use findIndex.
const array = [5, 4, 3, 1];
const n = 32;
array.push(n);
const sortedArray = array.sort();
const index = sortedArray.findIndex(el => el === n);
console.log(sortedArray, index)
Note that you sort could be improved if you're using numbers and you want them to be in ascending order after the sort:
const sortedArray = array.sort((a, b) => b < a);
You can use reduce function.
This approach returns an array of indexes of number 2 if this is repeated.
In this case, will return an array with only one index.
Look at this code snippet
var array = [5,4,3,1];
array.push(2);
var indexes = array.sort().reduce((a, n, i) => {
if (n === 2) {
a.push(i);
}
return a;
}, []);
console.log(JSON.stringify(indexes));
See, returns an array with only one index.
Resource
Array.prototype.reduce()
Hey guys so for example I have an array:
myArray[5,4,1,2,1,4,5,6,7,8,9,10,1,2,1,5,3,2]
I'm sorting that array:
[1, 1, 1, 1, 10, 2, 2, 2, 3, 4, 4, 5, 5, 5, 6, 7, 8, 9]
And I want to delete only the two duplicates so the array I want will be
[10,2,3,5,6,7,8,9]
So i'm using splice:
for (var index = 0; index < myArray.length +1; ++myArray) {
if(myArray[index+1]== myArray[index]) {
myArray.splice(index);
myArray.splice[index+1];
}
}
But when I'm pushing more of the of the numbers, the results seem unpredictable
How to do this properly?
To clarify: The purpose is to eliminate the numbers which repeat an even number of times.
Here's another method, which checks for an odd number of elements by subtracting the indexOf the key from the lastIndexOf the key after sorting:
var myArray = [5,4,1,2,1,4,5,6,7,8,9,10,1,2,1,5,3,2];
var result = myArray.sort().filter(function(key, idx) {
return myArray.indexOf(key) === idx && //handle first instance only
(myArray.lastIndexOf(key) - myArray.indexOf(key)) % 2 === 0;
});
console.log(result);
Here is an ECMAScript2015 solution:
var myArray = [5,4,1,2,1,4,5,6,7,8,9,10,1,2,1,5,3,2];
var count = myArray.reduce((count, num) =>
(count[num] = (count[num] || 0) + 1, count), {});
myArray = Object.keys(count).filter(num => count[num] % 2).map(Number);
console.log(myArray);
The count variable is an object of which the properties are the numbers in the original array. The value for each of these properties is the number of occurrences of that number in the original array.
The keys are then iterated to get only those into the final array that have a value (i.e. occurrences) that is odd. As object properties are iterated in numerical order (when numerical), the result is automatically sorted numerically.
About your code:
The for loop you have, has some issues:
for (var index = 0; index < myArray.length +1; ++myArray) {
if(myArray[index+1]== myArray[index]) {
myArray.splice(index);
myArray.splice[index+1];
}
}
Certainly you don't want to increment myArray, but index.
The boundary condition should not be length+1 but length-1 as in the body you have myArray[index+1] and don't want to go out of bounds there.
But more importantly, doing splice in your for loop will make the elements shift position, and as you then still increment index, you will skip elements.
In short, you should not use splice in such a loop. You can solve this by going in the reverse direction, and start at the end of the array working towards the beginning.
But the above proposed code does not have this problem and also saves you the step of sorting.
You can do this with two reduce and Object.keys(). First add values to object and then check each value with % 2 and add to array.
var myArray = [5,4,1,2,1,4,5,6,7,8,9,10,1,2,1,5,3,2];
var obj = myArray.reduce(function(o, e) {
o[e] = (o[e] || 0)+1;
return o;
}, {})
var result = Object.keys(obj).reduce(function(r, e) {
if(obj[e] % 2) r.push(Number(e));
return r;
}, []);
console.log(result)