How do I get an Array item's opposite index and value? - javascript

I have an array that I created using Array(...) and Array.prototype.map, like this:
var array_name = Array(255).map(function(undef, i) {
return i + 1;
});
The values of this array are:
[1, 2, 3, ..., 253, 254, 255]
This is an array that won't get modified, so the first value of this array will always be 1 and the last value of this array will always be 255.
I already know the index of each value is {value} - 1, so 200 would be 199, 199 would be 198, so on and so forth.
Let's say I want 255's opposite value, which would be 0, I could get that using array_name[0], but what if I wanted 200's opposite value, how would I know what the opposite index of 199 is so I could get it's value?

Do:
opposite_index = arr.length - index - 1
For example:
a = [1,2,3,4,5,6,7,8,9,10]
index = 3
a[index]
4
It's opposite is 7 so:
opposite_index = a.length - index - 1
a[opposite_index]
7
With reverse as per #Maheer Ali suggestion:
a.reverse()[index]
7

Your Array(255).map() create undefined array value.So do with Array#from length object.And pass your value.get index of the value and match with reverse array you get opposite value
let check = (val) => {
var array_name = Array.from({length:255},(a,b)=>b+1);
var nor_ind = array_name.indexOf(val);
var re_in = array_name.reverse(array_name).indexOf(val)
return ({nor_val:val,nor_ind:nor_ind,opp_val:re_in})
}
console.log(check(254))

First of all the code you provided doesn't create array [1,2,3...255]. It will create it will 255 empty items first you need to fill().
var arr = Array(255).fill().map((a,i) => i+1);
//Create an array which will have revese items.
let revarr= arr.reverse()
console.log(revarr[0]) //255
console.log(revarr[254]) // 1
If you don't want to create a reverse arr. You can create a function
var arr = Array(255).fill().map((a,i) => i+1);
const opp = (arr,num) => arr[arr.length - num - 1];
console.log(opp(arr,0));
console.log(opp(arr,254));

First, you gotta understand that there is weird behavior concerning Array(n).map(f) (it won't create the array you're expecting), see this answer for explanation, second, do this to get the opposite values:
/* fill it first with .fill(), see the question I linked for more explanation */
var array = Array(255).fill(undefined).map(function(undef, i) {
return i + 1;
});
function opposite(array, n) {
return array[array.length - n];
}
console.log(opposite(array, 255));
console.log(opposite(array, 200));
console.log(opposite(array, 199));
console.log(opposite(array, 1));
Notice that length - n is used instead of length - n - 1, because we're dealing with values from 1 to n, not from 0 to n - 1.

Subtract the index from (length-1) -> max index of the array
let arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
function findOpp(index, length) {
maxIndex = length - 1;
if (index <= maxIndex && index >= 0) {
return maxIndex - index;
} else {
return 'You have enter a wrong index';
}
}
console.log(findOpp(-1, 10));
console.log(findOpp(0, 10));
console.log(findOpp(1, 10));
console.log(findOpp(2, 10));
console.log(findOpp(4, 10));
console.log(findOpp(5, 10));
console.log(findOpp(6, 10));
console.log(findOpp(7, 10));
console.log(findOpp(8, 10));
console.log(findOpp(9, 10));
console.log(findOpp(10, 10));

Using Maheer Ali's suggestion I managed to get the desired result by reversing the array and using indexOf to get the index of that number:
var numbers = Array(255).map(function(v, i) {
return i + 1;
});
var opposite_brightness = numbers.reverse()[numbers.indexOf(brightness)];

Related

Split array into arrays of numbers where the sum is equal to a specific target

I need to create a function that take as parameter an array and a target. It should return an array of arrays where the sum of these numbers equals to the target
sumPairs(array, target) {
}
For example:
sumPairs([1, 2, 3, 4, 5], 7) // output : [[2, 5], [3, 4]]
I know I have to use map(), and probably reduce(), set(), or filter() maybe (I read their documentation in MDN but still cant find out). I tried some ways but I can't get it.
If you guys could help me to find out how to dynamically create arrays and push them into a new array..
I read there some solutions (Split array into arrays of matching values) but I hate to just use created functions without knowing what they really do or how they work.
Some very basic code for achieving it, Just run all over combinations and conditionally add the items you want.
function sumPairs(array, target) {
var res = [];
for(var i = 0; i < array.length; i++){
for(var j = 0; j < array.length; j++){
if(i!=j && array[i]+array[j]==target &&
res.filter((x)=> x[0] == array[j] && x[1] == array[i]).length == 0 )
res.push([array[i], array[j]]);
}
}
return res;
}
var result = sumPairs([1, 2, 3, 4, 5], 7);
console.log(result);
Option 2 - see this answer for more options (like using reduce)
function sumPairs(array, target) {
return array.flatMap(
(v, i) => array.slice(i+1).filter(w => (v!=w && v+w==target)).map(w=> [w,v])
);
}
var result = sumPairs([1, 2, 3, 4, 5], 7);
console.log(result);
"The exercise says that it sould be arrays of pairs that sum the
target value so I think only 2 items"
If you need a pair that matches a sum and you pick any number from the list, you are left with
the following equation to solve num + x = sum where we want to find x. E.g. if you picked 7 and the target sum is 10 then you know you are looking for a 3.
Therefore, we can first construct a counting map of the numbers available in our list linear (O(n)) time and then search for matches in linear time as well rather than brute forcing with a quadratic algorithm.
const nums = [1, 2, 3, 4, 5];
console.log(findSumPairs(nums, 7));
function findSumPairs(nums, sum) {
const countByNum = countGroupByNum(nums);
return nums.reduce((pairs, num) => {
countByNum[num]--;
const target = sum - num;
if (countByNum[target] > 0) {
countByNum[target]--;
pairs.push([num, target]);
} else {
countByNum[num]++;
}
return pairs;
}, []);
}
function countGroupByNum(nums) {
return nums.reduce((acc, n) => (acc[n] = (acc[n] || 0) + 1, acc), {});
}
Here's another implementation with more standard paradigms (e.g. no reduce):
const nums = [1, 2, 3, 4, 5];
console.log(findSumPairs(nums, 7));
function findSumPairs(nums, sum) {
const countByNum = countGroupByNum(nums);
const pairs = [];
for (const num of nums) {
const target = sum - num; //Calculate the target to make the sum
countByNum[num]--; //Make sure we dont pick the same num instance
if (countByNum[target] > 0) { //If we found the target
countByNum[target]--;
pairs.push([num, target]);
} else {
countByNum[target]++; //Didin't find a match, return the deducted num
}
}
return pairs;
}
function countGroupByNum(nums) {
const countByNum = {};
for (const num of nums) {
countByNum[num] = (countByNum[num] || 0) + 1;
}
return countByNum;
}
You can also sort your array and find all the pairs with given sum by using two pointer method. Place the first pointer to the start of the array and the second pointer to the end.
if the sum of the values at the two places is :
More than target: Decrement your second pointer by 1
Less than target: Increment your first pointer by 1
Equal to target: This is one possible answer, push them to your answer array and increment your first pointer by 1 and decrement your second pointer by 1.
This is more performant solution with complexity O(n*log(n))

How do you test whether both sides of an array total the same? | Javascript Algorithm

Question
You are going to be given an array of integers. Your job is to take that array and find an index N where the sum of the integers to the left of N is equal to the sum of the integers to the right of N. If there is no index that would make this happen, return -1.
For example:
Let's say you are given the array {1,2,3,4,3,2,1}: Your function will return the index 3, because at the 3rd position of the array, the sum of left side of the index ({1,2,3}) and the sum of the right side of the index ({3,2,1}) both equal 6.
Answer
function findEvenIndex(arr){
for(let i = 0; i <arr.length; i++){
let arr1 = arr.slice(0, (arr[i] - 1));
let arr2 = arr.slice((arr[i] + 1),);
let arr11 = arr1.reduce((total, item)=>{
return total + item;
}, 0);
let arr22 = arr2.reduce((total, item)=>{
return total + item;
}, 0);
if(arr11 === arr22){
return arr[i];
}
}
return -1;
}
console.log(findEvenIndex([1, 2, 3, 4, 3, 2, 1]))
console.log(findEvenIndex([1, 100, 50, -51, 1, 1]))
console.log(findEvenIndex([1, 2, 3,4,5,6]))
I can't see an error here, but it yields incorrect results. Any ideas?
You have this part:
let arr1 = arr.slice(0, (arr[i] - 1));
let arr2 = arr.slice((arr[i] + 1),);
This is incorrect: arr[i]. That is a value, eg in [2,4,6,8,10] arr[3]==8. You want to slice on the index itself:
let arr1 = arr.slice(0, i - 1);
let arr2 = arr.slice(i + 1,);
Please note: There is another error in the two lines :) I leave that to you. Hint: you're now slicing two values out of the array instead of one. Perform the following code in your head first, then somewhere where you verify your results.
let arr = [0,1,2,3,4]
let x = 2;
console.log(arr.slice(0, x - 1));
console.log(arr.slice(x + 1,));
You could also use the array method findIndex, which, we shouldn't be surprised to learn, finds an index in an array subject to a certain condition.
const sum = (ns) =>
ns .reduce ((total, n) => total + n, 0)
const findBalancedIndex = (ns) =>
ns .findIndex ((_, i) => sum (ns.slice (0, i)) === sum (ns.slice (i + 1)))
console .log (findBalancedIndex ([1, 2, 3, 4, 3, 2, 1]))
console .log (findBalancedIndex ([1, 100, 50, -51, 1, 1]))
console .log (findBalancedIndex ([1, 2, 3, 4, 5, 6]))
Here we include a simple helper function to find the sum of an array, and then we pass a function to findIndex which uses it twice on the elements before the index and those after it. We use the second parameter of the callback function, the index to do this. This means we are skipping the first parameter altogether, and rather than naming it with something like n, we use the somewhat common convention of calling it _, signalling a placeholder we won't use. Note that you don't need to subtract one from the right-hand boundary of slice, since that boundary value is already excluded. And of course, others have pointed out that you need to slice to the index and not the array value at that index.
This finds the first correct index. You would have to use a different technique if you wanted to find all such indices. (That it's possible to have more than one should be clear from arrays like [1, 2, 3, 0, 0, 0, 0, 3, 2, 1] -- the indices for all those 0s would work.)
you return arr[i] when you need to return just i

check if values in array have common difference

I have a sample array as
const arr=[0,2,4,6]
I want to check if they have a common difference in them, which is 2 and yes in above array.
There could be more efficient way to do this. I tried using a simple for loop as:
const arr = [0,2,4,6];
for(let i=0;i<arr.length-1;i++){
if(arr[i]+2==arr[i+1]){
console.log(true);
}
else{
console.log(false);
}
}
This could give me result as true,true,true and push all values to a new array then check if all are true and finally I would get true
It would be helpful if there is a more efficient way to do this; any help appreciated.
Assuming the array is sorted, you can do it pretty simply with .every().
const arr = [0,2,4,6];
const itvl = arr[1] - arr[0];
const result = arr.slice(0, -1).every((n, i) =>
itvl === arr[i + 1] - n
)
console.log(result);
This starts off by calculating the first interval, then it iterates the array (except the last index) using .every() to test that the next index minus the current one is equal to that pre-calculated index.
You can do this. It's better to stop as soon as you find a false rather than testing all the values.
const arr=[0,2,4,6]
var r = true
for (var i=1; i<arr.length-1 && r; i++) {
r = ((arr[i+1] - arr[i]) == (arr[i] - arr[i-1]))
}
console.log(r)
I assume what you mean by difference is the step value. For that, first find the difference between the first two elements ; then check whether the same difference holds for all consecutive values.
const arr = [0, 2, 4, 6];
let flag = true;
diff = arr[1] - arr[0];
for(let i = 1; i < arr.length-1; i++){
if(arr[i+1] - arr[i] != diff ){
flag = false;
break;
}
}
console.log(flag)
The code assumes the array size is atleast 2. Add an if guard if this is not always guaranteed.
Checks if numbers sum up to desired sum and if rest of numbers have same difference as desired in comments. (This should be a separate question.)
add up until s >= sum. return false if s isn't equal to set sum
if numbers left <= 2 return true
get difference of first 2 numbers
check difference of numbers, if not same difference return false
differences all same, return true
let arr = [0, 1, 3, 4, 6, 8, 10, 12];
const sum = 4
check = arr => {
let s = 0,
idx = arr.findIndex(x => (s+=x) >= sum ) + 1
if(s !== sum) return false
if(arr.length - idx < 3) return true
const diff = arr[idx+1] - arr[idx]
while(++idx<arr.length-1)
if(arr[idx+1] - arr[idx] !== diff) return false
return true
}
arr = [0, 1, 3, 4, 6, 8, 10, 12]
console.log(
check(arr)
)
arr = [0, 1, 3]
console.log(
check(arr)
)
arr = [0, 1, 3, 4, 6, 8, 10, 12, 11]
console.log(
check(arr)
)

Factorialise all numbers in array with .map

I have an array of numbers e.g. [2, 4, 5] and must get the factorials in a new array. E.g. [2, 24, 120]
I am using .map as you can see to perform the function on each integer in the array however, this does not work? I assume something is wrong with the recursive function?
Thanks.
function getFactorials(nums) {
if(nums > 1){
factarr = nums.map(x => x * (nums - 1));
}
return factarr;
}
You could take a function for the factorial and map the values.
The function has a recusive style with a check for the value. if the value is zero, then the function exits with one. Otherwise it returnd the product of the actual value and the result of the call of the function with decremented value.
The check uses an implict casting of a falsy to a boolean value for the conditional (ternary) operator ?:.
const fact = n => n ? n * fact(n - 1) : 1;
var array = [2, 4, 5],
result = array.map(fact);
console.log(result);
Just create a function that calculates the factorial of a given number then just use it as the callback for the map function.
As the main part is the way to calculate the factoriel, here's two manners to do that task
Factoriel function iterative way :
const fact = n => {
let f = 1,
i = n;
for(; i > 1; i--) f *= i;
return f;
};
console.log(fact(4)); /** outpuut: 24 **/
Factoriel function recursive way :
const fact = n => n > 1 ? n * fact(n - 1) : n;
console.log(fact(4)); /** outpuut: 24 **/
And the final code :
const arr = [2, 4, 5],
fact = n => n > 1 ? n * fact(n - 1) : n,
factArr = arr.map(i => fact(i));
console.log(factArr); /** output: [2, 24, 120] **/
You are doing the recursion wrong, my approach would be to define the factorial calculator as a separate function:
function getFactorials(nums) {
function factorial(n){
return n === 0 ? 1 : n * factorial(n - 1);
}
return nums.map(x => factorial(x));
}
console.log(getFactorials([0, 1, 2, 3, 4, 5 ,6]));
You need to calculate each factorial in array, your current code is not doing that. Consider following example:
function factorial(num) {
if (num === 0 || num === 1) {
return 1;
} else {
return num * factorial(num - 1);
}
}
const facts = [2, 4, 5];
const factsArr = facts.map(num => factorial(num));
In you code you was just multiplying each member of array by array itself.
Instead of doing it recursively, I took the solution from #Amin Jafari which uses reduce(). This function is quicker than the recursive solution.
First we generate an array. We do so by using Array(n + 1). n is the factorial so e.g. for 6! our n would be 6. We get the indices with keys() but Array() by itself only returns a truly empty array and keys() only returns an iterator. So we spread it and put the result of that into a new array. Thus, we have e.g. [0,1,2,3,4,5,6] (for n + 1 with n = 6). We exclude the 0 with slice(1).
Afterwards we finally apply reduce. Reduce iterates over all elements, applies a function while keeping track of an accumulator. Our accumulator here is the current product. So what happens is that 1 * 2 gets calculated and the result saved in a, our accumulator. Then we multiply a with the next value, so 2 * 2* and this happens until we went through our whole self generated array.
This function based on reduce we can then use to transform each value in our original array with map().
const factorial = n => [...Array(n+1).keys()].slice(1).reduce((a,c) => a * c),
data = [2, 4, 5];
let res = data.map(v => factorial(v));
console.log(res);
I know that this post has a lot of answers already, but I might have something to add:
If you are planning to use the recursive function a lot to calculate factorials, let's say you need this in a browser game every .5 secs, you will notice that it is consuming a lot of resources, mainly your time 😉.
My proposition is:
calculate the factorials once
store them in the app state
look them up instead of calculating them
example code (based on Nina Scholz's anwer):
// create this earlier, put it in the application state
const state = {lookupFact: []}
const fact = n => n ? n * fact(n - 1) : 1;
// only calculate the factorials once
function lookupFact(par) {
if (state.lookupFact.length == 0) {
for (var i = 0; i <= 170; i++) {
state.lookupFact[i] = fact(i)
}
}
return state.lookupFact[par]
}
// use it like this later on
console.log(lookupFact(1), lookupFact(10), lookupFact(5))
As I said, you should use this only if you have to calculate factorials all the time.
var arr = [2,3,4,5,6,7]
arr.map((value, ind) => {
var facts = 1;
for (value ;value > 0 ;value--) {
facts = facts *value;
}
console.log(facts);
})

Finding a non-consecutive number pair in an array

Given an array with a minimum length of 3 and a maximum length of 5, which always contains uniquely occurring integers from 0 to 4 in ascending order, I need to pick out two non-consecutive numbers from it. Non-consecutive refers to their numeric value, not their position in the array.
To clarify, here are examples of valid arrays:
[ 1, 2, 3 ]
[ 0, 1, 2, 4 ]
[ 0, 3, 4 ]
For the arrays above, valid answers could be, respectively:
[ 1, 3 ]
[ 0, 2 ], [ 0, 4 ] or [ 1, 4 ]
[ 0, 3 ] or [ 0, 4 ]
Furthermore, in those cases where there is more than one valid answer, I need it to be selected at random, if at all possible (for instance I don't want to favor sequences that begin with the lowest number, which is what would occur if I always began checking from left to right and stopped checking as soon as I found one valid solution).
What would be the most efficient way of tackling this problem in Javascript?
You could use two nested iterations and build an new array for choosing as random result.
function getNonConsecutives(array) {
return array.reduce((r, a, i, aa) => r.concat(aa.slice(i + 2).map(b => [a, b])), []);
}
console.log(getNonConsecutives([ 0, 1, 2, 4 ]));
.as-console-wrapper { max-height: 100% !important; top: 0; }
According to Bee157's answer, you could use a random choice with a constraint, like length for the first index and add the needed space for the second index.
The problem is, due to the nature of choosing the first number first, the distribution of the result is not equal.
function getNonConsecutives(array) {
var i = Math.floor(Math.random() * (array.length - 2));
return [
array[i],
array[Math.floor(Math.random() * (array.length - 2 - i)) + 2 + i]
];
}
console.log(getNonConsecutives([ 0, 1, 2, 4 ]));
demoFn(array) {
var i,j, y =[];
for (i=0; i<=array.length;i++) {
for (j = i + 1; j <= array.length; j++) {
if (array[j] && array[i]) {
if (array[j] !== array[i] + 1) {
y.push([array[i], array[j]]);
}
}
}
}
}
Take a random array and check it.
You can create a function using recursion that will pick random number in each iteration and loop all other elements and if condition is met add to array.
function findN(data) {
data = data.slice();
var r = []
function repeat(data) {
if (data.length < 2) return r;
var n = parseInt(Math.random() * data.length);
data.forEach(function(e, i) {
if (i != n) {
var a = data[n];
if (Math.abs(a - e) != 1 && r.length < 2) r.push(n < i ? [a, e] : [e, a])
}
})
data.splice(n, 1);
repeat(data)
return r;
}
return repeat(data)
}
console.log(findN([1, 2, 3]))
console.log(findN([0, 1, 2, 4]))
console.log(findN([0, 3, 4]))
Something like this should do it:
const pick = nums => {
// Pick a random number
const val = nums[Math.floor(Math.random() * nums.length) + 0];
// Filter out any numbers that are numerically consecutive
const pool = nums.filter(n => Math.abs(n - val) > 1);
// Pick another random number from the remainer
const other = pool[Math.floor(Math.random() * pool.length) + 0];
// Sort + return them
return [val, other].sort();
};
console.log(pick([0, 1, 2, 4]));
since you state that the array ellemnts are all unique, and that they are sorted.
It should suffice to take an random element
var index1=Math.floor(Math.random()*arr.length)
now any other element (except maybe the elemnts on position (index1 +/- 1) are not consecutive
So a new random element can be chosen excluding the first index.
var index2=Math.floor(Math.random()*arr.length);
if(index2==index1){
index2+=((index2<arr.length-1)?1:-1);
}
if(Math.abs(arr[index1]-arr[index2])<=1){
if(index2==0 && arr.length<4){
//set index2 to arr.length-1 and do check again, if not ok=> no result
if(!(arr[index1]-arr[arr.length-1]>=-1)){
return [arr[arr.length-1],arr[index1]];
}
}
else if(index2==arr.length-1 && arr.length<4){
//set index2 to 0 and do check again, if not ok=> no result
if(!(arr[index1]-arr[0]<=1)){
return [arr[0],arr[index1]];
}
}
else{
//if index2>index1 index2++
//else index2--
//always OK so no further check needed
index2+=(index2>index1?1:-1);
return [arr[index1],arr[index2]];
}
}
else{
//ok
return [arr[index1,arr[index2]];
}
return false;
if speed is not important, you can use a filter on the array to calculate a new array with all elements differing more then 1 unit of arr[index1]. and randomly select a new number from this new array.
Other attempt
function getNonConsecutive(arr){
var index1,index2,arr2;
index1=Math.floor(Math.random()*arr.length);
arr2=[].concat(arr);
arr2.splice((index1!==0?index1-1:index1),(index!==0?3:2));
if(arr2.length){
index2=Math.floor(Math.random()*arr2.length);
return [arr[index1],arr2[index2]];
}
else{
//original array has length 3 or less
arr2=[].concat(arr);
arr2.splice(index1),1);
for (var j=0,len=arr.length;j<len;j++){
if(Math.abs(arr1[index1]-arr2[j])>1){
return [arr[index1],arr2[j]];
}
}
}
return false
}

Categories

Resources