I have to write a function switchMaxMin(tab, n) that swaps the maximum element with the minimum element in an n-element array tab. We assume that all elements of the array are distinct (i. e. there are not a few maxima or minima). I don't know how to do this
I started to write the code and I came up with this:
var tab = new Array(6, 4, 65, 34, 67, 89, 45, 7, 35, 79, 23, 56, 87, 12, 38, 9);
var min = tab[0];
var max = tab[0];
document.write("Tablica: ");
for (i = 1; i < tab.length; i++) {
document.write(tab[i] + ", ");
if (min > tab[i]) {
min = tab[i];
}
if (max < tab[i]) {
max = tab[i];
}
}
document.write("<br /><br />Max: " + max);
document.write("<br />Min: " + min);
To swap the elements you have also to store the indices of the max and min elements
if (min > tab[i]) {
min = tab[i];
minIndex = i;
}
if (max < tab[i]) {
max = tab[i];
maxIndex = i;
}
Then you can reassign it by a classical swap function
function swapper(maxInd, minInd) {
let temp = tab[maxInd];
tab[maxInd] = tab[minInd]
tab[minInd] = temp;
}
var tab = new Array(6, 4, 65, 34, 67, 89, 45, 7, 35, 79, 23, 56, 87, 12, 38, 9);
var min = tab[0];
var max = tab[0];
var minIndex = 0;
var maxIndex = 0;
document.write("Tablica: ");
for (let i = 1; i < tab.length; i++) {
document.write(tab[i] + ", ");
if (min > tab[i]) {
min = tab[i];
minIndex = i;
}
if (max < tab[i]) {
max = tab[i];
maxIndex = i;
}
}
swapper(maxIndex, minIndex);
document.write("<br /><br />Max: " + max);
document.write("<br />Min: " + min);
document.write("<br /> After the swap " + tab.join(","));
function swapper(maxInd, minInd) {
let temp = tab[maxInd];
tab[maxInd] = tab[minInd]
tab[minInd] = temp;
}
Just another way to do it, slightly less efficient, but fewer lines of code.
var tab = new Array(6, 4, 65, 34, 67, 89, 45, 7, 35, 79, 23, 56, 87, 12, 38, 9);
var min = Math.min.apply(null,tab);
var minIndex = tab.indexOf(min);
var max = Math.max.apply(null,tab);
var maxIndex = tab.indexOf(max);
var temp = tab[minIndex]
tab[minIndex] = tab[maxIndex]
tab[maxIndex] = temp;
console.log(tab)
Related
I have the following code and the logic seems to be correct. However, when I run the last console.log ( 'console.log(bills)'), nothing shows up for its output.
const bills = [22, 295, 176, 440, 37, 105, 10, 1100, 86, 52]
const tipsTotal = [];
let sum = 0;
const calcTip = function(bill) {
return bill >= 50 && bill <= 300 ? bill * .15 : bill * .20;
}
for (let i = 0; i < bills.length; i++) {
const value = calcTip(bills[i]);
calcTip(tipsTotal.push(value));
}
console.log(tipsTotal);
const calcAverage = function(arr) {
for (let i = 0; arr.length; i++) {
sum = sum + arr[i];
}
let average = sum / arr.length;
return average;
}
console.log(calcAverage(bills));
The sum variable should be declared inside calcAverage.
You forgot to check if the loop index reached the end of the array: i < arr.length
const bills = [22, 295, 176, 440, 37, 105, 10, 1100, 86, 52];
const tipsTotal = [];
const calcTip = function(bill) {
return bill >= 50 && bill <= 300 ? bill * .15 : bill * .20;
}
for (let i = 0; i < bills.length; i++) {
const value = calcTip(bills[i]);
calcTip(tipsTotal.push(value));
}
console.log(tipsTotal);
const calcAverage = function(arr) {
let sum = 0;
for (let i = 0; i < arr.length; i++) {
sum = sum + arr[i];
}
let average = sum / arr.length;
return average;
}
console.log(calcAverage(bills));
Reduce works great in these cases
const bills = [22, 295, 176, 440, 37, 105, 10, 1100, 86, 52];
const sum = bills.reduce((sum,bill) => {
const tip = bill >= 50 && bill <= 300 ? bill * .15 : bill * .20;
sum += (bill+tip);
return sum;
},0)
console.log(sum.toFixed(2),(sum/bills.length).toFixed(2));
I have this array:
var mes_dias = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
I'd like to know if is there somehow to create a new array only if the sum of them are less than a global array using a loop or something, example
var dia = 122;
var dia_new = [31, 28, 31, 30]; //This because they sum less than the given var (dia).
Thanks for your answer
Use a Javascript for-loop and check the count in every iteration.
If the count is lesser than dia then push that number into the array.
for(var i = 0; i < mes_dias.length && (count + mes_dias[i] < dia); i++)
var mes_dias = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
var dia = 122;
var count = 0;
var array = [];
for(var i = 0; i < mes_dias.length && (count + mes_dias[i] < dia); i++) {
count += mes_dias[i];
array.push(mes_dias[i]);
}
console.log(array);
.as-console-wrapper {
max-height: 100% !important
}
if dia is an array of numbers, and its sum is the max days for the new array:
The reduce function will sum the elements in array_dia.
var dia = array_dias.reduce((a, n) => a += n, 0);
var mes_dias = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
var array_dias = [30, 30, 31, 31];
var dia = array_dias.reduce((a, n) => a += n, 0);
console.log(dia)
var count = 0;
var array = [];
for(var i = 0; i < mes_dias.length && (count + mes_dias[i] < dia); i++) {
count += mes_dias[i];
array.push(mes_dias[i]);
}
console.log(array);
.as-console-wrapper {
max-height: 100% !important
}
You can reduce your array into a new array:
let mes_dias = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
let dia = 120;
let dia_new = mes_dias.reduce( (dia_acc, dias) => {
dia -= dias;
if (dia >= 0)
dia_acc.push(dias);
return dia_acc;
}, []);
EDIT 1: Based on Angel Politis' answer, another elegant solution can be:
let dia_new = mes_dias.slice(0, mes_dias.findIndex( (dias) => (dia -= dias) < 0));
EDIT 2: Based on Ele's answer, this way offers same, if not better, performance and is more readable in my view. Remember, in worst case scenario we loop 12 times.
let array = [],
sum = 0;
// Add days until they sum to more than 'dia'
for(let i = 0; i < mes_dias.length; ++i) {
sum += mes_dias[i];
if (sum > dia)
break;
array.push(mes_dias[i]);
}
var mes_dias = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
var dia = 122;
var total = 0;
var newarray = new Array();
for(var i = 0; i < mes_dias.length && (total + mes_dias[i]) <= dia; i++) {
newarray.push(mes_dias[i]);
total = total + mes_dias[i];
console.log(newarray);
}
One way to achieve what you want would be using a loop in which you:
progressively sum the elements of mes_dias.
cache the index of the last element, if sum <= dia.
Then, you can use slice to get the portion of the array until the last index.
Snippet:
var
arr = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31], // mes_dias
max = 122, // dia
last,
newArr;
/* Iterate over every element of the array until sum > max and save the index. */
for (let i = 0, sum = 0, l = arr.length; i < l && sum <= max; sum += arr[++i]) {
last = i;
}
/* Get the portion of the array until the index. */
newArr = arr.slice(0, last);
/* Log the result. */
console.log(newArr);
I have written a function to perform wave-sort as shown below. The resulting array should begin with a number bigger than the next one but my code is not doing that. For example if the input is:
[73, 80, 40, 86, 14, 96, 10, 56, 61, 84, 82, 36, 85]
...it gives an output of
[ 86, 96, 84, 85, 80, 82, 61, 73, 40, 56, 14, 36, 10 ]
instead of starting with a bigger number than the next, which is 96.
function waveSort(arr){
arr = arr.sort(function(a, b) {
return b - a;
});
for (var i = 1; i < arr.length; i += 2) {
if (arr[i-1] > arr[i]) {
var temp = arr[i];
arr[i] = arr[i-1];
arr[i-1] = temp;
}
if (i+1 < arr.length && arr[i+1] > arr[i]) {
temp = arr[i];
arr[i] = arr[i+1];
arr[i+1] = temp;
}
}
return arr;
}
You have explicitly designed your function to start with a lower value.
In the first if you detect a situation where the first value is greater than the second, and if so, you swap them (when i = 1):
if (arr[i-1] > arr[i]) {
So it is normal you end up with a smaller value at index 0 than at index 1.
If you want your array to start with a "wave high", then change the conditions in your two ifs:
function waveSort(arr){
arr = arr.sort(function(a, b) {
return b - a;
});
for (var i = 1; i < arr.length; i += 2) {
if (arr[i-1] < arr[i]) {
var temp = arr[i];
arr[i] = arr[i-1];
arr[i-1] = temp;
}
if (i+1 < arr.length && arr[i+1] < arr[i]) {
temp = arr[i];
arr[i] = arr[i+1];
arr[i+1] = temp;
}
}
return arr;
}
var waved = waveSort([73, 80, 40, 86, 14, 96, 10, 56, 61, 84, 82, 36, 85]);
console.log(JSON.stringify(waved));
function waveSort(arr){
arr.sort((a,b)=>b-a);
for(var i=1;i<arr.length;i+=2){
var tmp = arr[i];
arr[i]=arr[i+1];
arr[i+1]=tmp;
}
return arr;
}
var wavesorted = waveSort([73, 80, 40, 86, 14, 96, 10, 56, 61, 84, 82, 36, 85]);
console.log(wavesorted);
Another way would be to define a swap function and call it within the actual function like:
const swap = (arr, i, j) => ([arr[i], arr[j]] = [arr[j], arr[i]]);
const waveSort = (arr) => {
arr = arr.sort((a, b) => b - a);
for(let i = 1; i < arr.length; i += 2){
if(arr[i-1] < arr[i]) {
swap(arr, i-1, i)
}
if(i+1 < arr.length && arr[i+1] < arr[i]) {
swap(arr, i+1, i)
}
}
return arr;
}
var waved = waveSort([73, 80, 40, 86, 14, 96, 10, 56, 61, 84, 82, 36, 85]);
console.log(JSON.stringify(waved));
`
I am trying to implement binary search in javascript. I don't know what is going wrong with my script. The page becomes unresponsive whenever I click the search button.Thanks in advance.
var i,print,arr;
arr = [1,2,3,4,5,6,7,8,9,10];
print = document.getElementById("showArray");
for(i = 0; i < arr.length; i++){
print.innerHTML += arr[i] + " ";
}
function binarySearch(searchValue){
var lowerIndex, higherIndex, middleIndex,writeResult;
lowerIndex = 0;
higherIndex = arr.length;
writeResult = document.getElementById("showResult");
while(lowerIndex <= higherIndex){
middleIndex = (higherIndex + lowerIndex) / 2;
if(searchValue == arr[middleIndex]){
writeResult.innerHTML = "PRESENT";
consol.log('Present');
break;
}
else if(searchValue > arr[middleIndex]){
lowerIndex = middleIndex + 1;
}
else if(searchValue < arr[middleIndex]){
higherIndex = middleIndex - 1;
}
}
}
<button onclick = "binarySearch(1)">SEARCH</button>
<p id = "showArray" style = "font-size: 40px; padding:0px;"> </p>
<p id = "showResult">Result is:</p>
Try something like
Array.prototype.br_search = function (target)
{
var half = parseInt(this.length / 2);
if (target === this[half])
{
return half;
}
if (target > this[half])
{
return half + this.slice(half,this.length).br_search(target);
}
else
{
return this.slice(0, half).br_search(target);
}
};
l= [0,1,2,3,4,5,6];
console.log(l.br_search(5));
The main problem, you have is not to use the integer part of the calculation for the middleIndex. This makes it impossible to check for a value at a given index of the array, because the index must be an integer number.
var i,
print = document.getElementById("showArray"),
arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
for (i = 0; i < arr.length; i++) {
print.innerHTML += arr[i] + " ";
}
function binarySearch(searchValue) {
var lowerIndex = 0,
higherIndex = arr.length - 1,
middleIndex,
writeResult = document.getElementById("showResult");
while (lowerIndex <= higherIndex) {
middleIndex = Math.floor((higherIndex + lowerIndex) / 2);
if (searchValue == arr[middleIndex]) {
writeResult.innerHTML = "PRESENT " + middleIndex;
break;
}
if (searchValue > arr[middleIndex]) {
lowerIndex = middleIndex + 1;
} else {
higherIndex = middleIndex - 1;
}
}
}
<button onclick="binarySearch(2)">SEARCH</button>
<p id="showArray" style="font-size: 40px; padding:0px;"> </p>
<p id="showResult">Result is:</p>
An iterative example of binary search without break.
Running time: log2(n)
function search(array, target) {
let min = array[0]
let max = array.length - 1;
let guess;
while (max >= min) {
guess = Math.floor((min+max)/2);
if (array[guess] === target) {
return guess;
} else if (array[guess] > target) {
max = guess - 1;
} else {
min = guess + 1;
}
}
return -1;
}
const primes = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97];
console.log(search(primes, 67));
Sorry for my english, really really tired...
Imagine two arrays:
var a = [-10, 5, 0, 5, 10, 15];
var b = [-20, 0, 20, 40, 60, 80];
Every value of each array increments by the same number (a by 5 and b by 20).
I would like to find a way to put the zero on the same position on both arrays.
Keep in mind that:
each serie has the same number of elements
you can change the min and max value of each array (the original min and max of a serie have to be a part of the serie, check the example below)
each value of the array increments by the same number, you can change this value
The expected result could be something like
var a = [-10, 5, **0**, 5, 10, 15];
var b = [-60, -30, **0**, 30, 60, 90];
b increments now by 30 and the original min (-20) and max (8) values are included in the interval.
Any idea on how to do that using javascript?
Why I'd like to do that? To solve something like that:
http://peltiertech.com/Excel/Charts/AlignXon2Ys.html
Thanks in advance
Rob
The following is a result of code iteration based on comments. Previous code has been removed for clarity, but remains available in edit history.
This one fixes the zero in the middle of a series, then adjusts values according to the initial requirements. Also rounding to the nearest 5 (previous code was inadequate in that regard, sorry). HTH.
function develop(data) {
if (data.length < 3) {
return data;
}
var lower = data[0];
var upper = data[data.length - 1];
var index = (data.length - 1) / 2;
var numLeft = Math.floor(index);
var numRight = Math.ceil(index);
var leftStep = findStep(lower, numLeft, false);
var rightStep = findStep(upper, numRight, true);
var step = roundStep(Math.max(leftStep, rightStep), 5);
var result = [];
for (var ii = 0; ii < data.length; ii++) {
result[ii] = step * (ii - numLeft);
}
return result;
// ---
function findStep(boundary, numEntries, positive) {
if (positive && boundary <= 0 || !positive && boundary >= 0) {
return 1;
}
return Math.abs(Math.ceil(boundary / numEntries));
}
function roundStep(step, roundTo) {
if (step < roundTo) {
return step;
}
return Math.ceil(step / roundTo) * roundTo;
}
}
function test() {
var testData = [
[-10, -5, 0, 5, 10, 15],
[-20, 0, 20, 40, 60, 80],
[0, 72, 144, 216, 288, 360],
[-30, -25, -20, -15, -10, 0]
];
var results = [];
for (var ii = 0; ii < testData.length; ii++) {
var data = testData[ii];
results.push(JSON.stringify(data) + " => " + develop(data));
}
document.getElementById("results").innerHTML = results.join("<br>");
}
<input type="button" value="test()" onclick="test()" />
<div id="results"></div>
This seems to work, but I'm probably doing couple thins not necessary
var setIndex = function (arr1, arr2) {
var arr1Min = arr1[0];
var arr2Min = arr2[0];
var arr1Max = arr1[arr1.length-1];
var arr2Max = arr2[arr2.length-1];
var length = arr1.length;
var newRatio;
var newMin;
var newMax;
var ratioArr1 = arr1Max/arr1Min;
var ratioArr2 = arr2Max/arr2Min;
if(ratioArr1 < ratioArr2){
newMin = calcNewMin(arr1Min, arr1Max, ratioArr2);
newMax = ratioArr2 * newMin;
newRatio = (newMax - newMin)/(length-1);
arr1 = [];
for(var i = 0; i < length; i++){
arr1.push(newMin + (i * newRatio));
}
return [arr1, arr2];
} else {
newMin = calcNewMin(arr2Min, arr2Max, ratioArr1);
newMax = ratioArr1 * newMin;
newRatio = (newMax - newMin)/(length-1);
arr2 = [];
for(var i = 0; i < length; i++){
arr2.push(newMin + (i * newRatio));
}
return [arr1, arr2];
}
};
var calcNewMin = function(min, max, ratio){
var count = 1;
var newMin = min;
var newMax = max;
while(newMax <= max){
count++;
newMin = min - count;
newMax = newMin * ratio;
}
return newMin;
};
Compare the array ranges first, if one array includes the range of the other one then the answer is a series with an increment higher than the array that increments where the start of the range is:
0 - increment * (position of 0)
In your example:
var a = [-10, 5, 0, 5, 10, 15];
var b = [-20, 0, 20, 40, 60, 80];
b includes the range of a, so any series that have an increment higher than b and obeys the rules at the beginning are valid solutions to the problem:
[-20, 0, 20, 40, 60, 80]
[-21, 0, 21, 42, 63, 84]
[-22, 0, 22, 44, 66, 88]
...
[-60, 0, 60, 120, 180, 240]
All of these series include the range of a.
It gets a little bit trickier when the ranges overlap:
[-10, 0, 10, 20, 30]
[ 0, 20, 40, 60, 80]
The idea behind is the same. We'll pick the series with the smallest value:
[-10, 0, 10, 20, 30]
From this, we'll need to find a higher increment so that it satisfies:
start + (inc * length) > max of other series.
Where start:
0 - (inc * pos of 0 in picked series)
Moving stuff around you get:
inc > (max value / (length - pos of 0 in picked series))
So in this example:
inc > 80 / (5 - 2)
inc > 80 / 3
inc > 26.666
Lets try it with an increment of 27 and a start of -27:
[-27, 0, 27, 54, 81]
Now, that you we know how to solve the problem, lets try it with code:
function getMinMax(a, b){
var last = a.length - 1,
min = a[0] < b[0] ? a : b,
max = a[last] > b[last] ? a : b;
return { min : min, max : max };
}
function closestInc(range){
if(range.min === range.max){
return range.min[1] - range.min[0];
} else {
var last = range.min.length - 1,
maxValue = range.max[last],
posOfCero = range.min.indexOf(0);
return (maxValue/(range.min.length - posOfCero));
}
}
So, all the possible answers would be any series with an increment value bigger than closestInc(a, b) and a start of -closestInc(a,b) * posOfCero.
Here's a function that prints out all possible values slowly:
function createSeries(inc, posOfCero, count) {
var series = [],
start = -(inc * posOfCero);
for (var i = 0; i < count; i++) {
series.push(start + (inc * i));
}
return series;
}
var a = [-10, 5, 0, 5, 10, 15],
b = [-20, 0, 20, 40, 60, 80],
ranges = getMinMax(a, b),
inc = closestInc(ranges),
posOfCero = ranges.min.indexOf(0);
setTimeout(function printSeries(i) {
console.log(createSeries(inc + 1, posOfCero, range.min.length));
setTimeout(printSeries, 1000, i + 1);
}, 1000, 1);
A snippet below:
function getMinMax(a, b) {
var last = a.length - 1,
min = a[0] < b[0] ? a : b,
max = a[last] > b[last] ? a : b;
return {
min: min,
max: max
};
}
function closestInc(range) {
if (range.min === range.max) {
return range.min[1] - range.min[0];
} else {
var last = range.min.length - 1,
maxValue = range.max[last],
posOfCero = range.min.indexOf(0) + 1;
return (maxValue / (range.min.length - posOfCero));
}
}
function createSeries(inc, posOfCero, count) {
var series = [],
start = -(inc * posOfCero);
for (var i = 0; i < count; i++) {
series.push(start + (inc * i));
}
return series;
}
//var a = [-10, 5, 0, 5, 10, 15],
// b = [-20, 0, 20, 40, 60, 80],
var a = [-10, 0, 10, 20, 30],
b = [ 0, 20, 40, 60, 80],
ranges = getMinMax(a, b),
inc = closestInc(ranges),
posOfCero = ranges.min.indexOf(0);
setTimeout(function printSeries(i) {
console.log(createSeries(Math.round(inc + i), posOfCero, ranges.min.length));
setTimeout(printSeries, 1000, i + 1);
}, 1000, 1);
A last note, this aren't all possible series to match your rules (there might still be some valid increments between the series).
You can use Array.push and Array.unshift like this jsFiddle