Related
This question already has answers here:
Check array in JS - is list sorted? [duplicate]
(9 answers)
Closed 7 months ago.
how can I determine when the first X numbers of an array is in order AND the last element in 0? i.e the array is
1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,0
I currently have this, but this relies on the array always being the same, which isn't very flexibile
const sorted = (array) => {
const solved = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0]
return (JSON.stringify(array) == JSON.stringify(solved))
}
You could do something as simple as this:
const checkArray = (arr) => {
if(arr[arr.length-1] != 0){
return false;
}
const nums = arr.slice(0, arr.length - 1);
const sortedArr = [...nums].sort((a, b) => a - b);
for (let i = 0; i < nums.length; i++) {
if(nums[i] != sortedArr[i]){
return false;
}
}
return true;
}
console.log(checkArray([1,2,3,0])); // true
console.log(checkArray([1,2,3,4])); // false
console.log(checkArray([1,3,2,0])); // false
Basically the steps are:
Check if last element is 0, else do an early return.
Create a sorted version of the first part of the array (the one with the numbers)
Check if the numbers part is equal to the sorted array. If any element is different return false
In the end you return true only if every condition is verified.
This is generic enough so that if in the future you want to change the sorting type you can just act on the sort function (for example if you want to make it descending).
First define a generic function to verify that a segment of an array is sorted, then define a second function that uses the first to see the first values are sorted, and add a check for the final value:
function isSegmentSorted(array, start=0, end=array.length) {
for (let i = start + 1; i < end; i++) {
if (array[i - 1] > array[i]) return false;
}
return true;
}
function isSortedWithExtraZero(array) {
return array.at(-1) === 0 &&
isSegmentSorted(array, 0, array.length - 1);
}
var array = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,0];
console.log(isSortedWithExtraZero(array));
We can use every function for that. With !idx we exclude the first index 0, then we check if idx is less than the length of your array. If so, check if it is sorted, else check it it equals to zero.
const solutions = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0];
const sorted = solutions.every((val, idx, arr) =>
!idx || (idx < solutions.length - 1 ? arr[idx - 1] <= val : val === 0)
);
console.log(sorted);
There are examples of aesthetically pleasing trees:
These are examples of not aesthetically pleasing trees
That, given an array A consisting of N integers, where A[K] denotes the height of the K-th three, returns the number of ways of cutting out one tree, so that the remaining trees aesthetically pleasing. If it is not possible to achieve the desired result, your function should return -1. If the trees are already aesthetically pleasing without any removal your function should return 0.
Expected Result A1 = [1, 2, 3, 4, 2, 5]; This pattern can never be form visually aesthetical so, function should return -1.
Expected Result A2 = [1, 3, 1, 2]; this pattern is already in visually aesthetically pleasant so it should return 0.
I tried to solve it but it's not working and I only got 1 result to all. Can someone help me code this in javascript?
Results Example:
Example test: [3, 4, 5, 3, 7]
WRONG ANSWER (got 1 expected 3)
Example test: [1, 2, 3, 4]
WRONG ANSWER (got 1 expected -1)
Example test: [1, 3, 1, 2]
CORRECT ANSWER
My Code:
function solution(A) {
if (A.length < 3) {
return A[0] != A[1] ? 0 : 1;
}
var count = 0;
for (var i = 0; i < A.length - 2 ; i += 2) {
var a = A[i];
var b = A[i+1];
var c = A[i + 2];
if (!(a - b > 0 && b - c < 0) && !(a - b < 0 && b - c > 0)) {
count++;
}
}
return count;
}
You could break the problem into single tasks and check if an array is pleasant, then return zero or count pleasant subarrays.
The key function toggles the direction greater/smaller with a function and checks if the next pair is either greater, if the previous pair is smaller or vice versa.
To start, it needs to get the opposite of the actual direction, because it changes the directions first before checking.
function pleasant(array) {
function isPleasant(array) {
const
toggle = { gt: 'lt', lt: 'gt' },
fns = { gt: (a, b) => a > b, lt: (a, b) => a < b };
let dir = fns.gt(array[0], array[1]) ? 'lt' : 'gt';
return array
.slice(1)
.every((v, i) => fns[dir = toggle[dir]](array[i], v));
}
function count() {
return array.reduce((c, _, i, a) => c + isPleasant([
...a.slice(0, i),
...a.slice(i + 1)
]), 0);
}
return isPleasant(array)
? 0
: count() || -1;
}
console.log(pleasant([3, 4, 5, 3, 7])); // 3
console.log(pleasant([1, 2, 3, 4])); // -1
console.log(pleasant([1, 3, 1, 2])); // 0
console.log(pleasant([1, 1, 1, 1])); // -1
I have 2 questions, how can I get value instead of value inside array and how can I make this code shorter and declarative.
arr = [16, 4, 11, 20, 2]
arrP = [7, 4, 11, 3, 41]
arrTest = [2, 4, 0, 100, 4, 7, 2602, 36]
function findOutlier(arr) {
const isPair = (num) => num % 2 === 0
countEven = 0
countOdd = 0
arr1 = []
arr2 = []
const result = arr.filter((ele, i) => {
if (isPair(ele)) {
countEven++
arr1.push(ele)
} else {
countOdd++
arr2.push(ele)
}
})
return countEven > countOdd ? arr2 : arr1
}
console.log(findOutlier(arrTest))
Filtering twice may be more readable.
even = arr.filter((x) => x % 2 == 0);
odd = arr.filter((x) => x % 2 == 1);
if (even.length > odd.length) {
return even;
} else {
return odd;
}
If you're looking to do this with one loop, consider using the array reduce method to put each number into an even or odd bucket, and then compare the length of those buckets in your return:
function findOutlier(arr) {
const sorted = arr.reduce((acc, el) => {
acc[el % 2].push(el);
return acc;
},{ 0: [], 1: [] })
return sorted[0].length > sorted[1].length ? sorted[1] : sorted[0];
}
const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9];
console.log(findOutlier(arr));
Note that this does not handle when the arrays are the same length gracefully (right now it'll just return the odd array).
You could take an object with the wanted part for collecting and add a short circuit if one of the types has a count of one and the others have a count greater than one.
const
isPair = num => num % 2 === 0,
findOutlier = array => {
count = { true: [], false: [] };
for (const value of array) {
count[isPair(value)].push(value);
if (count.true.length === 1 && count.false.length > 1) return count.true[0];
if (count.false.length === 1 && count.true.length > 1) return count.false[0];
}
};
console.log(...[[16, 4, 11, 20, 2], [7, 4, 11, 3, 41], [2, 4, 0, 100, 4, 7, 2602, 36]].map(findOutlier));
Here is an solution that selects the even or odd array based on the modulo result.
function findOutlier(integers) {
const even = [], odd = [], modulos = [even, odd];
for (const integer of integers) {
modulos[Math.abs(integer % 2)].push(integer);
}
return even.length > odd.length ? odd : even;
}
console.log(findOutlier([2, 4, 0, 100, 4, 7, 2602, 36]));
You unfortunately do need Math.abs() to handle negative values, because -3 % 2 == -1.
See: JavaScript % (modulo) gives a negative result for negative numbers
However the name findOutlier lets me assume there is only a single outlier within the provided list. If this is the case you can optimize the algorithm.
function findOutlier(integers) {
// With less than 3 integers there can be no outlier.
if (integers.length < 3) return;
const isEven = (integer) => integer % 2 == 0;
const isOdd = (integer) => !isEven(integer);
// Determine the outlire based on the first 3 elements.
// If there are 0 or 1 integers even, the outlire is even.
// if there are 2 or 3 integers even, the outlier is odd.
const outlier = integers.slice(0, 3).filter(isEven).length < 2
? isEven
: isOdd;
return integers.find(outlier);
}
console.log(findOutlier([2, 4, 0, 100, 4, 7, 2602, 36]));
You can do this without creating intermediate arrays by simply comparing each element to its neighbors and returning that element if it is different to both, or undefined if no outliers are found. This returns in the same iteration in which the outlier is first encountered, and returns the value itself and not an array.
function findOutlier(array) {
const
len = array.length,
isEven = (n) => n % 2 === 0;
for (const [i, value] of array.entries()) {
let
prev = array[(i-1+len)%len], // loop around if < 0 (first element)
next = array[(i+1)%len]; // loop around if >= length (last element)
if (isEven(value) !== isEven(prev) && isEven(value) !== isEven(next)) {
return value;
}
}
return undefined;
}
const arrays = [[16, 4, 11, 20, 2], [7, 4, 11, 3, 41], [2, 4, 0, 100, 4, 7, 2602, 36]]
console.log(...arrays.map(findOutlier));
Now that OP clarified the requirements (at least in a comment) this allows a different approach:
function findOutlier(array) {
let odd = undefined, even = undefined;
for (let i of array) {
let isEven = i % 2 == 0;
if (odd !== undefined && even !== undefined)
return isEven ? odd : even;
if (isEven) even = i;
else odd = i;
}
if (odd !== undefined && even !== undefined)
return array[array.length-1];
}
console.log(findOutlier([2,4,6,8,10,5]))
The algorithm will iterate the array, and store the lastest found odd and even numbers, respectively.
If we discovered both an odd and an even number already, with the current number we can decide, which of them is the outlier: If the current number is even, it's at least the second even number we found. Thus, the found odd number must be the outlier. The same applies vice versa if the current number is odd. The special case, if the outlier is the last element of the array, is checked with an additional condition after the loop.
If all numbers are odd or even (ie there is no outlier) this function will return undefined. This algorithm does not throw an error, if the preconditions are not met, ie if there is more than one outlier.
I was making a JavaScript program that would check if array contains consecutive values like 1,2,3,4,5 or 5,4,3,2,1. Now, I've been successful in checking if it contains numbers in order like 1,2,3,4,5 but for some reason I just can't seem to make it work for checking in reverse order (like 5,4,3,2,1)
Here's my code:
let nums = prompt("Enter number separated by hyphen");
let numcol = nums.split("-");
let intnumcol = [];
for (let i = 0; i < numcol.length; i++) {
intnumcol.push(parseInt(numcol[i]));
}
for (let j = 0; j < intnumcol.length; j++) {
if (j > 0) {
if (intnumcol[j] === ++intnumcol[j - 1] || intnumcol[j]===--intnumcol[j-1] ) {
let flag = true;
if (!flag)
break;
if (j == intnumcol.length - 1 && flag == true) {
console.log("consecutive");
break;
}
} else {
console.log("not consecutive")
break;
}
}
}
Here, in this statement:
if (intnumcol[j] === ++intnumcol[j - 1] || intnumcol[j]===--intnumcol[j-1] )
I do have the OR condition for checking reversed order values but for some reason, it is not working. I don't know why. So please help me.
Here's the JS Fiddle link : https://jsfiddle.net/Lrwagc3m/
Also, please don't confuse this to be the duplicate of some other question because my questions asks for why this certain code doesn't work for checking reverse order consecutive values and for knowing the code to make it work.
I have put together some functions to help you determine if an array contains only numbers in ascending or descending order. The most important is the consecutiveChecker which receives the array and a function that compares 2 consecutive elements. If there are any 2 consecutive elements which don't respect this condition, the function will return false. If we reached the end of array, it will return true.
As you can see, I have 2 filters prepared, one that checks ascending order and another one for checking descending order, which are later used in consecutiveAscOrDescChecker, for which I've written some test cases and some code similar to yours to prompt the user for some numbers and return back the answer.
const ascendingOrder = (a, b) => a - b === -1;
const descendingOrder = (a, b) => ascendingOrder(b, a);
const consecutiveChecker = (array, consecutiveFilter) => {
for (let i = 1; i < array.length; i++) {
if (!consecutiveFilter(array[i - 1], array[i])) {
return false;
}
}
return true;
}
const consecutiveAscOrDescChecker = (array) =>
consecutiveChecker(array, ascendingOrder) ||
consecutiveChecker(array, descendingOrder);
const testCases = [
[1, 2, 3, 4, 5], // true
[1, 2, 3, 4, 6], // false
[5, 4, 3, 2, 1], // true
[-1, 0, 1], // true
[1, 0, -1], // true
[1, 2, 3, 3, 4], // false
[1], // true
[] // true
];
for (const array of testCases) {
console.log(array, consecutiveAscOrDescChecker(array));
}
const numbers = prompt("Enter numbers separed by '-'")
.split("-")
.map(x => parseInt(x));
alert(`${numbers} array is ${consecutiveAscOrDescChecker(numbers) ? 'consecutive' : 'not consecutive'}`);
Note: this setup let's you check other things easily, e.g. what if you wanted to check if consecutive elements grow by 2? Easy:
const growByTwo = consecutiveChecker(array, (a, b) => a - b === -2);
Wanna check if an array elements grows/shrinks by a particular number? Easy:
const consecutiveBy = (x) => {
const ascendingByX = (a, b) => a - b === -x;
const descendingByX = (a, b) => ascendingByX(b, a);
return (array) =>
consecutiveChecker(array, ascendingByX) ||
consecutiveChecker(array, descendingByX);
}
const consecutiveByThree = consecutiveBy(3);
console.log(consecutiveByThree([1, 3, 5])); // false
console.log(consecutiveByThree([1, 4, 7])); // true
With this function, consecutiveAscOrDescChecker would be as easy as:
const consecutiveAscOrDescChecker = consecutiveBy(1);
console.log(consecutiveAscOrDescChecker([1, 2, 4])); // false
console.log(consecutiveAscOrDescChecker([1, 2, 3])); // true
Note that you can't use Math.abs with consecutiveChecker as it would give you a different outcome, e.g.
consecutiveChecker([1, 2, 1, 0, -1, 0], (a, b) => Math.abs(a - b) === 1); would return true(!!) because the difference between any 2 consecutive elements, ascending or descending, is 1, which is a different problem than yours.
you can try something like the below which will help you to find out whatever input was provided in ascending or descending order
AscendingOrDescending = (inputString) => {
const arrayOfNumbers= Array.from(inputString);
const asscendingResult = arrayOfNumbers.every((number,index,array) => {
return index < array.length ? Number(number) + 1 === Number(array[index+1]) || Number(number) - 1 === Number(array[index-1]) : true;
});
return asscendingResult ? 'string is in ascending or descending order' : 'string is not in ascending or descending order'
}
console.log(AscendingOrDescending("123456"))
I'm trying to solve this task of finding the unique element inside an array.
So far I managed to solve 95%, but I'm failing on 0. I get an error saying that expected 0 and got 1.
I should get //10, which it does, but after I'm failing the test online. For all other values it has passed.
Any ideas about how to solve this and what I'm missing here?
function findOne(arr) {
let x = arr[0];
for (let i of arr) {
if (i === x) {
continue;
} else {
x = i;
}
return x;
}
}
console.log(findOne([3, 10, 3, 3, 3]));
I don't really understand your code. You start with the first value in the array, then you loop through the array, skipping anything that's the same, and then return the first one that's not the same. That won't find unique values, it'll just find the first value that doesn't equal the first value. So for instance, try it on the array [1,2,2,2,2] and you'll get a result of 2 instead of 1, even though that's clearly wrong.
Instead, you can create a map of each value and its incidence, then filter by the ones that equal 1 at the end.
function findOne(arr) {
const incidences = arr.reduce((map, val) => {
map[val] = (map[val] || 0) + 1;
return map;
}, {});
const values = Object.keys(incidences);
for (let i = 0; i < values.length; ++i) {
if (incidences[values[i]] === 1) { return values[i]; }
}
return null;
}
EDIT The above won't preserve the type of the value (i.e. it'll convert it to a string always, even if it was originally a number). To preserve the type, you can use an actual Map instead of an object:
function findOne(arr) {
const incidences = arr.reduce((map, val) => {
map.set(val, (map.get(val) || 0) + 1);
return map;
}, new Map());
const singletons = Array.from(incidences).filter(entry => entry[1] === 1);
return singletons.map(singleton => singleton[0]);
}
Consider the following:
Recall that a span = max - min + 1;
Let Partition P1 be span from 0..span-1;
Let Partition P2 be span from span..(2*span)-1:
Place a number in P1 if it is not in P2.
Place a number in P2 if it is already in P1.
Once the number is in P2, do not consider it again.
If a number is in P1 then it is unique.
You can get all values that appear once, by using a map to count how many times each element has appeared. You can then reduce that map into an array of unique values:
const findUnique = arr => {
const mapEntries = [...arr.reduce((a, v) => a.set(v, (a.get(v) || 0) + 1), new Map()).entries()]
return mapEntries.reduce((a, v) => (v[1] === 1 && a.push(v[0]), a), [])
}
console.log(findUnique([3, 10, 3, 3, 3]))
console.log(findUnique([1, 2, 3, 2, 4]))
console.log(findUnique([4, 10, 4, 5, 3]))
If you don't care about multiple unique values, you can just sort the array and use logic, rather than checking every value, provided the array only contains 2 different values, and has a length greater than 2:
const findUnique = arr => {
a = arr.sort((a, b) => a - b)
if (arr.length < 3 || new Set(a).size === 1) return null
return a[0] === a[1] ? a[a.length-1] : a[0]
}
console.log(findUnique([3, 10, 3, 3, 3]))
console.log(findUnique([3, 3, 1]))
console.log(findUnique([3, 1]))
console.log(findUnique([3, 3, 3, 3, 3]))
Your code is complex, Try this
function findOne(arr) {
const uniqueItems = [];
arr.forEach(item => {
const sameItems = arr.filter(x => x === item);
if (sameItems.length === 1) {
uniqueItems.push(item);
}
});
return uniqueItems;
}
console.log(findOne([0, 1, 1, 3, 3, 3, 4]));
I'm getting all unique items from passed array, It may have multiple unique item
this is a way simpler and fast:
function findOne(arr) {
const a = arr.reduce((acc, e) => {
e in acc || (acc[e] = 0)
acc[e]++
return acc
}, {})
return Object.keys(a).filter(k => a[k] === 1)[0] || null
}