Odd number of elements in an array - javascript

When trying to figure out how to get the median value of an array, I first wanted to figure out if the number of elements in the array is odd or even.
If the number is odd then the console will log the element in the middle.
If there's an even number of elements I want the console to log 'Not an odd number of numbers'.
I'm sure there's an easier way to get the median of an array, but I want to figure that out by myself. Right now I just need help with why the console logs the number 1 in my second test of an array, even though there is an even number of elements in that array? It worked fine in the first and third test but not the second one...why?
function median (arr) {
let sorted = arr.sort((a, b) => a-b)
let midIndex = sorted.splice(0, sorted.length / 2)
if (arr.length %2 != 0) {
return midIndex[midIndex.length-1]
} else {
return "Not an odd number of numbers"
}
}
try {
let result = median([4, 8, 2, 4, 5])
console.log(result) // -> 4
result = median([-5, 1, 5, 2, 4, 1]) // -> 1
console.log(result)
result = median([5, 1, 1, 1, 3, -2, 2, 5, 7, 4, 5, 6]) // -> Not an odd number of numbers
console.log(result)
} catch (e) {
console.error(e.message)
}

Because splice actually changes the length of the original array - it does not create a new array. You can see this by taking a note of the length before calling splice
function median (arr) {
var initLength = arr.length;
let sorted = arr.sort((a, b) => a-b)
let midIndex = sorted.splice(0, sorted.length / 2)
console.log(initLength, arr.length);
if (arr.length %2 != 0) {
return midIndex[midIndex.length-1]
} else {
return "Not an odd number of numbers"
}
}
try {
let result = median([4, 8, 2, 4, 5])
//console.log(result) // -> 4
result = median([-5, 1, 5, 2, 4, 1]) // -> 1
//console.log(result)
result = median([5, 1, 1, 1, 3, -2, 2, 5, 7, 4, 5, 6]) // -> Not an odd number of numbers
//console.log(result)
} catch (e) {
console.error(e.message)
}
So splicing an array of 6 in half gives a length of 3 which is odd. Instead use the original array length and it does what you expected:
function median (arr) {
var initLength = arr.length;
let sorted = arr.sort((a, b) => a-b)
let midIndex = sorted.splice(0, sorted.length / 2)
if (initLength %2 != 0) {
return midIndex[midIndex.length-1]
} else {
return "Not an odd number of numbers"
}
}
try {
let result = median([4, 8, 2, 4, 5])
console.log(result) // -> 4
result = median([-5, 1, 5, 2, 4, 1]) // -> 1
console.log(result)
result = median([5, 1, 1, 1, 3, -2, 2, 5, 7, 4, 5, 6]) // -> Not an odd number of numbers
console.log(result)
} catch (e) {
console.error(e.message)
}

Related

Find the longest sub array of consecutive numbers with a while loop

I want to write a function with a while-statement that determines the length of the largest consecutive subarray in an array of positive integers. (There is at least one consecutive array.) For instance:
Input: [6, 7, 8, 6, 12, 1, 2, 3, 4] --> [1,2,3,4]
Output: 4
Input: [5, 6, 1, 8, 9, 7] --> [1,8,9]
Output: 3
Normally I would try to use for-loops and the array.push method later on, however, to get more practice I wanted to use a while-loop and another 'array-lengthening' method, not sure how it's called, see below.
My try:
function longestSub (input) {
let i=0;
let idx=0;
let counterArr=[1]; //init. to 1 because input [4,5,3] equals sub-length 2
while(i<input.length) {
if (input[i]+1 > input[i]) {
counterArr[0+idx] += 1
}
else {
i=input.indexOf(input[i]); //should start loop at this i-value again
idx +=1;
counterArr[0+idx] = 1; //should init new array index
}
i++
}
return Math.max(...counterArr)
}
My idea was that the else-statement would reset the if-statement when it fails and start again from the position it failed at with updated variables. It would also initialize another array index with value 1 that gets subsequently updated afterwards with the if-statement.
Finally I have a counterArr like [1,2,3] where 3 stands for the largest consecutive subarray. Thanks everyone reading this or helping a beginner like me to get a deeper understanding of Javascript.
Here is a simple solution using while loop:
let arr =[6, 7, 8, 6, 12, 1, 2, 3, 4]
let endIndx = 0, maxLength = 0, indx = 1,tempMax = 0;
while (indx < arr.length) {
if (arr[indx] > arr[indx - 1])
tempMax++;
else {
if (maxLength <= tempMax) {
maxLength = tempMax+1
endIndx = indx
tempMax=0;
}
}
++indx
}
if (maxLength < tempMax) {
maxLength = tempMax
endIndx = indx
}
console.log("Sub array of consecutive numbers: ", arr.slice(endIndx-maxLength,endIndx))
console.log("Output :",maxLength)
You could take an approach which just counts the length and checks with the max found length if the continuous items.
function longestSub(input) {
let i = 1, // omit first element and use later element before this index
max = 0,
tempLength = 1; // initialize with one
if (!input.length) return 0;
while (i < input.length) {
if (input[i - 1] < input[i]) {
tempLength++;
} else {
if (max < tempLength) max = tempLength;
tempLength = 1;
}
i++;
}
if (max < tempLength) max = tempLength;
return max;
}
console.log(longestSub([])); // 0
console.log(longestSub([6, 7, 8, 6, 12])); // 3
console.log(longestSub([5, 6, 1, 2, 8, 9, 7])); // 4
console.log(longestSub([6, 7, 8, 6, 12, 1, 2, 3, 4, 5])); // 5
Unless this really is a learning exercise, I'd rather focus on the approach than on the implementation.
Create a function that slices an array of numbers into arrays of consecutive numbers:
The first two conditions deal with the simplest cases:
If input is empty, output is empty [] -> []
If input is exactly one element, the output is known already [42] -> [[42]]
Then comes the "meat" of it. The output is an array of array. Let's start by creating the first sub array with the first element of the initial array. Let's use [6, 7, 8, 6, 12, 1 ,2 ,3, 4, 5] as the input.
Start with [[6]] then iterate over [7, 8, 6, 12, 1 ,2 ,3, 4, 5]. Here are the result at each iteration:
7 > 6 true -> [[6,7]]
8 > 7 true -> [[6,7,8]]
6 > 8 false -> [[6],[6,7,8]]
12 > 6 true -> [[6,12],[6,7,8]]
1 > 12 false -> [[1],[6,12],[6,7,8]]
2 > 1 true -> [[1,2],[6,12],[6,7,8]]
3 > 2 true -> [[1,2,3],[6,12],[6,7,8]]
4 > 3 true -> [[1,2,3,4],[6,12],[6,7,8]]
5 > 4 true -> [[1,2,3,4,5],[6,12],[6,7,8]]
const slices =
xs =>
xs.length === 0 ? []
: xs.length === 1 ? [[xs[0]]]
: xs.slice(1).reduce
( ([h, ...t], x) =>
x >= h[h.length - 1]
? [h.concat(x), ...t]
: [[x], h, ...t]
, [[xs[0]]]
);
slices([6, 7, 8, 6, 12, 1 ,2 ,3, 4, 5]);
//=> [ [1, 2, 3, 4, 5]
//=> , [6, 12]
//=> , [6, 7, 8]
//=> ]
Then you create a function that takes an array of slices and return the biggest one:
const max_slices =
xs =>
xs.reduce
( (a, b) =>
a.length > b.length
? a
: b
);
max_slices(slices([6, 7, 8, 6, 12, 1 ,2 ,3, 4, 5]));
//=> [1, 2, 3, 4, 5]

How to find elements in array JavaScript where array[i] = i?

I need to find elements in an array of numbers where arr[i] === i, meaning the element must be equal to the array index.
They must be found with using recursion, not just by cycle.
I would be very thankful, if someone help, because I've spent many hours and can't do anything.
I've tried to use Binary Search but it doesn't work. In the end I've got only the empty array.
function fixedPointSearch(arr, low, high) {
let middle = Math.floor((high - low) / 2);
console.log( low, high, middle )
let arrRes = [];
if (arr[middle] === middle)
{ arrRes.push(arr[middle]); }
else if (arr[middle] > middle)
{ fixedPointSearch(arr, middle + 1, high); }
else
{ fixedPointSearch(arr, low, middle - 1); }
return arrRes;
}
const arr1 = [-10, -3, 2, 3, 6, 7, 8, 9, 10, 12, 16, 17];
console.log(fixedPointSearch(arr1, 0, arr1.length - 1));
To do this recursively, you presumably want to recurse on smaller and smaller arrays, but that means you need to also update the index you're checking on each call. One of the simplest ways to do this is just to include an index in the parameters to your function and increment it on each recursive call. This is one way to do so:
const fixedPointSearch = ([x, ...xs] = [], index = 0) =>
x == undefined
? []
: [... (x === index ? [x] : []), ... fixedPointSearch (xs, index + 1)]
console .log (
fixedPointSearch([-10, -3, 2, 3, 6, 7, 8, 9, 10, 12, 16, 17])
)
It's debatable whether that version or the following one is easier to read, but they are doing essentially the same thing:
const fixedPointSearch = ([x, ...xs] = [], index = 0) =>
x == undefined
? []
: x === index
? [x, ... fixedPointSearch (xs, index + 1)]
: // else
fixedPointSearch (xs, index + 1)
There is a potential problem, though. Running this over a large array, we could hit the recursion depth limit. If the function were tail-recursive, that problem would simply vanish when JS engines perform tail-call optimization. We don't know when that will be, of course, or even it it will actually ever happen, even though it's been specified for five years. But it sometimes makes sense to write to take advantage of it, on the hope that it will one day become a reality, especially since these will still work as well as the non-tail-call version.
So a tail-recursive version might look like this:
const fixedPointSearch = ([x, ...xs] = [], index = 0, res = []) =>
x == undefined
? res
: fixedPointSearch (xs, index + 1, x === index ? [...res, x] : res)
You can solve this w/o additional temporary arrays and parameters, by simply shortening the array in each step:
const myArray = [0, 5, 2, 4, 7, 9, 6];
function fixedPointSearch(arrayToTest) {
if (arrayToTest.length === 0) {
return [];
}
const lastIndex = arrayToTest.length - 1;
const lastItem = arrayToTest[lastIndex];
const remainingItems = arrayToTest.slice(0, lastIndex);
return lastItem === lastIndex
? [...fixedPointSearch(remainingItems), lastItem]
: fixedPointSearch(remainingItems);
}
console.log(fixedPointSearch(myArray));
If you want to find all the elements you should start from the beginning of the array, not the middle and loop through all the indexes.
The idea is for the recursion is to define the end condition.
Then you check if arr[i] === i to update the results array.
Then you make the recursive call with the index incremented and with the updated results array.
function fixedPointSearch(arr, i, results) {
// End condition of the recursion
if (i === arr.length - 1 || arr.length === 0) {
return results;
}
if (arr[i] === i) {
results.push(i);
}
// Recursive call
return fixedPointSearch(arr, i + 1, results);
}
const arr1 = [-10, -3, 2, 3, 6, 7, 8, 9, 10, 12, 16, 17];
console.log(fixedPointSearch(arr1, 0, []));
console.log(fixedPointSearch([], 0, []));
console.log(fixedPointSearch([9, 8, 7], 0, []));
The idiomatic solution in JavaScript uses Array.prototype.filter -
const run = (a = []) =>
a.filter((x, i) => x === i)
console.log(run([ 0, 1, 2, 3, 4, 5 ])) // [0,1,2,3,4,5]
console.log(run([ 3, 3, 3, 3, 3, 3 ])) // [3]
console.log(run([ 7, 1, 7, 3, 7, 5 ])) // [1,3,5]
console.log(run([ 9, 9, 9, 9, 9, 9 ])) // []
Above it should be clear that recursion isn't required for the job. But there's nothing stopping you from using it, if you wish -
const filter = (test = identity, a = [], i = 0) =>
{ /* base */
if (i >= a.length)
return []
/* inductive: i is in bounds */
if (test(a[i], i))
return [ a[i], ...filter(test, a, i + 1) ]
/* inductive: i is in bounds, a[i] does not pass test */
else
return filter(test, a, i + 1)
}
const run = (a = []) =>
filter((x, i) => x === i, a)
console.log(run([ 0, 1, 2, 3, 4, 5 ])) // [0,1,2,3,4,5]
console.log(run([ 3, 3, 3, 3, 3, 3 ])) // [3]
console.log(run([ 7, 1, 7, 3, 7, 5 ])) // [1,3,5]
console.log(run([ 9, 9, 9, 9, 9, 9 ])) // []
For recursion, you'll need an end condition. Something like
const findElementValueIsPositionInarray = arr => {
let results = [];
const find = i => {
if (arr.length) { // as long as arr has values
const value = arr.shift(); // get value
results = i === value // check it
? results.concat(value)
: results;
return find(i+1); // redo with incremented value of i
}
return results;
};
return find(0);
}
console.log(findElementValueIsPositionInarray([2,3,4,3,9,8]).join());
console.log(findElementValueIsPositionInarray([2,3,4,91,9,8]).join());
console.log(findElementValueIsPositionInarray([0,1,2,87,0,5]).join());
.as-console-wrapper { top: 0; max-height: 100% !important; }
I don't know why you want it through recursion:-
But anyway following should help you:-
let ans = [];
function find(arr,index,ans)
{
if(index==arr.length-1)
{
if(arr[index]==index){
ans.push(arr[index])
}
return;
}
if(arr[index]==index){
ans.push(arr[index])
}
find(arr,index+1,ans);
}
const arr1 = [-10, -3, 2, 3, 6, 7, 8, 9, 10, 12, 16, 17];
find(arr1,0,ans);
console.log(ans);

Create Frequency Map Using Map - JavaScript

Trying to solve this Codwars Kata.
Given an array, find the duplicates in that array, and return a new array of those duplicates. The elements of the returned array should appear in the order when they first appeared as duplicates.
Examples:
[1, 2, 4, 4, 3, 3, 1, 5, 3, '5'] ==> [4, 3, 1]
[0, 1, 2, 3, 4, 5] ==> []
I have:
function duplicates(arr) {
arr.sort((value, index) => value - index);
let duplicates = [];
for (let i = 0; i < arr.length; i++) {
if (arr[i] === arr[i + 1]) {
duplicates.unshift(arr[i]);
}
}
//filter out duplicates within "duplicates"
duplicates = duplicates.filter((value, index) =>
duplicates.indexOf(value) == index);
return duplicates;
}
console.log(duplicates([1, 2, 4, 4, 3, 1, 5, '5']));
This is passing all tests except for one:
Expected: '[1, 4]', instead got: '[4, 1]'
And I'm not sure why - unfortunately it does not display the test case.
It was suggested that another way to create a frequency map, however, is with Map. How would I do this?
I tried:
function duplicates(arr) {
let map = new Map([arr]);
return map;
}
console.log(duplicates([1, 2, 4, 4, 3, 1, 5, '5']));
and this doesn't create a frequency map.
What other suggestions would you have?
NOTE - "5" and 5 should not count as the same value.
EDIT - Initially, tried to create a frequencyMap like this:
function duplicates(arr) {
let map = {};
arr.forEach((value, index) => {
if (!map[value]) {
map[value] = 0;
}
map[value] += 1;
})
return map;
}
console.log(duplicates([1, 2, 4, 4, 3, 1, 5, '5']));
But in this case, "5" and 5 are considered to be the same value. I don't know how else to check for duplicates - sorting disrupts the order in which the duplicates appear; and creating a frequencyMap count numbers and strings as the same thing.
Here's an idea that should work:
Create a Map (map keys distinguish type so 5 is a different key than "5")
Use filter to go through the items in your array. As you go through keep count of how many times you've seen an item in your Map. Return true from the filter only when the count (before you've increased it) is 1. That's the second time you've seen that item.
The filter should return your answer:
function duplicates(arr) {
let counts = new Map()
return arr.filter(n => {
let count = counts.get(n)
counts.set(n, count ? count+1 : 1)
return count === 1
})
}
console.log(duplicates([1, 2, 4, 4, 3, 1, 5, '5']));
Might not be the most efficient solution, but it solves the challenge. Note, I'm using js object to mimic a Map
function duplicates(arr) {
// TODO: return the array of duplicates from arr
const map = {};
const dup = {};
for (const val of arr) {
let key = val;
if (typeof val === 'string') {
key = `${val}_str`;
}
if (map[key]) {
dup[val] = true;
} else {
map[key] = true;
}
}
return Object.keys(dup)
.map( d => (!Number.isInteger(parseInt(d))) ? d : Number(d));
}
console.log(duplicates([1, 2, 4, 4, 3, 1, 5, '5']));

Difference between same value in array using only one loop javascript

How to find the difference between the min and max indexes of the same value in an array with one loop with complexity exactly O(N)?
For example, given array A:
[4, 6, 2, 2, 6, 6, 1];
the function returns 4.
I'd use reduce to remember the first index of each value, then update the last value and maximum spread as I went along, e.g.
var data = [4, 6, 2, 2, 6, 6, 1];
function getMaxIndexSpread(data) {
return data.reduce(function(acc, value, index) {
if (value in acc) {
acc[value].lastIndex = index
} else {
acc[value] = {firstIndex: index, lastIndex: index};
}
var spread = acc[value].lastIndex - acc[value].firstIndex;
if (acc.maxSpread < spread) acc.maxSpread = spread;
return acc;
}, {maxSpread: 0}).maxSpread;
}
console.log(getMaxIndexSpread(data));
There's likely a funkier way, but this makes sense to me.
var data = [4, 6, 2, 2, 6, 6, 1];
console.log(Math.max(...data.map((v,i) => i - data.indexOf(v))));
var arr = [4, 6, 2, 2, 6, 6, 1];
function test(arr) {
var resultArr = [];
arr.map(function (v, i, a) {
for (var j = arr.length - 1; j >= 0; j--) {
if (v == arr[j]) {
resultArr.push({value: v, result: j - i});
// console.log(v+'的折扣值'+(j-i));
break;
}
}
})
resultArr.sort(function (a, b) {
return b.result - a.result;
})
console.log(resultArr[0])
}
test(arr);
Try with Array#filter .filter the array without max and min value .Then find max value in filtered array .... its spread syntax
var data = [4, 6, 2, 2, 6, 6, 1];
function bet(data) {
return Math.max(...data.filter(a => a != Math.max(...data) && a != Math.min(...data)))
}
console.log(bet(data))

Jumble numbers in an array such that no two adjacent numbers are same using JavaScript

The idea it to basically not have repeated values in the array with similar values.
An example input array:
input = [1,2,2,2,2,3,4,5,6,7,8,9]
Expected output to be something like this:
desiredOutput = [1,2,3,2,4,2,5,2,6,2,7,8,9]
I have tried putting this in a for loop where it checks with the next item and if it is same, swaps the values. The problem is when I have continuous similar values.
This proposal features
count of elements and store it in an appropriate object,
check whether spread is possible (e.g. not here [1, 1, 1, 1, 3, 3]),
round robin with the elements, so
maximum distance between the same elements.
How does it work?
As example I take this array: [1, 2, 2, 2, 2, 3, 4, 5, 6, 7, 8, 9]
Build an object with the count of the elements, store it with the element as key.
length = {
"1": 1, "2": 4, "3": 1, "4": 1, "5": 1, "6": 1, "7": 1, "8": 1, "9": 1
}
Select the property with the largest value: length[2] = 4
Make a new array with the length of the previous value and fill it with empty arrays.
output = [[], [], [], [], []]
Check if a spreaded array is possible. If not, return.
Set k to the key of the biggest value of a property.
k = '2'
If truthy, proceed. Otherwise go to 11.
Set l to the value of length[k].
l = 4
Iterate over l and push k to the end of the array with the index of i % outputLength. Increase i.
Delete property k.
Proceed with 5.
Return the flat output array.
output first then continued
array 0: 2 1 6
array 1: 2 3 7
array 2: 2 4 8
array 3: 2 5 9
return: 2 1 6 2 3 7 2 4 8 2 5 9
distance | | | | is equal
function spread(input) {
function findMaxKey() {
var max = 0, key;
Object.keys(length).forEach(function (k) {
if (length[k] > max) {
max = length[k];
key = k;
}
});
return key;
}
var length = input.reduce(function (r, a) {
r[a] = (r[a] || 0) + 1;
return r;
}, {}),
i = 0, k = findMaxKey(), l,
outputLength = length[k],
output = Array.apply(Array, { length: outputLength }).map(function () { return []; });
if (input.length - outputLength < outputLength - 1 ) {
return; // no spread possible
}
while (k = findMaxKey()) {
l = length[k];
while (l--) {
output[i % outputLength].push(k);
i++;
}
delete length[k];
}
return output.reduce(function (r, a) { return r.concat(a) }, []);
}
console.log(spread([1, 2, 2, 2, 2, 3, 4, 5, 6, 7, 8, 9]));
console.log(spread([1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2]));
console.log(spread([1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3]));
console.log(spread([1, 1, 1, 1, 3, 3]));
console.log(spread([1, 1, 3]));
.as-console-wrapper { max-height: 100% !important; top: 0; }
maybe that could help you:
for(var i = 1; i < input.length; i++) {
if(input[i-1] == input[i]) {
var j = i;
while(j < input.length && input[j] == input[i]) {
j++;
}
var el = input[j];
input[j] = input[i];
input[i] = el;
}
}
Greedy Approach Using Max Heap
The idea is to greedily put the highest frequency numbers first.
Construct a max heap where every node is a tuple that stores the number & it's frequency.
Then extract the head of the max heap (the highest frequency node) and add it's value to the resultant array.
If there's a previous element then add it back to the heap.
Decrement the frequency of the extracted node and store it in prev, so that it can be added back after one iteration.
Finally return the solution if it exists otherwise return the string "Not Possible".
function solution(arr) {
const maxHeap = Array.from(
arr.reduce((m, i) => m.set(i, (m.get(i) ?? 0) + 1), new Map())
).sort(([, a], [, b]) => b - a);
const res = [];
let prev = null;
while (maxHeap.length) {
const maxNode = maxHeap.shift();
res.push(maxNode[0]);
maxNode[1] -= 1;
if (prev) {
maxHeap.push(prev);
maxHeap.sort(([, a], [, b]) => b - a);
prev = null;
}
if (maxNode[1] > 0) {
prev = maxNode;
}
}
return res.length < arr.length ? "Not Possible" : res;
}
console.log(JSON.stringify(solution([1, 2, 2, 2, 2, 3, 4, 5, 6, 7, 8, 9])));
console.log(JSON.stringify(solution([1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2])));
console.log(JSON.stringify(solution([1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3])));
console.log(JSON.stringify(solution([1, 1, 1, 1, 3, 3])));
console.log(JSON.stringify(solution([1, 1, 3])));
Note: I've not implemented a Max Heap (because it's tedious), I've simulated it with Array.prototype.sort.

Categories