JavaScript Callback Confusing Behavior - javascript

Having trouble writing a callback function in JavaScript that returns a mapped array with each number in it incremented by one.
arr = [1, 2, 3, 4];
const each = (elements, cb) => {
for (let i = 0; i < elements.length; i++) {
cb(elements[i], i);
}
};
const map = (elements, cb) => {
const mappedArr = [];
each(elements, item => {
mappedArr.push(cb(item));
});
return mappedArr;
};
const cb = (e) => {
e += 1;
}
const newArr = map(arr, cb);
console.log(newArr) // [ undefined, undefined, undefined, undefined ]
Your patience is appreciated in advance; I'm still learning and trying to understand callbacks. Please help me understand what I did wrong here.

Your cb is not returning anything at the moment, so the return value defaults to undefined. Use an arrow function with implicit return (no { }s) instead, so that the incremented value is returned.
Also, try to avoid implicitly creating global variables (with your arr):
const arr = [1, 2, 3, 4];
const each = (elements, cb) => {
for (let i = 0; i < elements.length; i++) {
cb(elements[i], i);
}
};
const map = (elements, cb) => {
const mappedArr = [];
each(elements, item => {
mappedArr.push(cb(item));
});
return mappedArr;
};
const cb = e => e + 1;
const newArr = map(arr, cb);
console.log(newArr)

return in missing in cb function.Check this:
arr = [1, 2, 3, 4];
const each = (elements, cb) => {
for (let i = 0; i < elements.length; i++) {
cb(elements[i], i);
}
};
const map = (elements, cb) => {
const mappedArr = [];
each(elements, item => {
mappedArr.push(cb(item));
});
return mappedArr;
};
const cb = (e) => {
return e += 1;
}
const newArr = map(arr, cb);
console.log(newArr) // [ undefined, undefined, undefined, undefined ]

Related

Get dates from array and disable those dates from calendar that repeat more than twice

I want to get dates from array which are repeated 3 times so I can disable those dates from calendar.
function disbaleDate() {
const arr = [
"1/6/2022",
"12/6/2022",
"4/6/2022",
"6/6/2022",
"1/6/2022",
"1/6/2022",
];
const increment = [];
for (let i = 1; i < arr.length; i++) {
for (let j = 0; j < i; j++) {
if (arr[j] === arr[i]) {
increment.push(arr[i]);
}
}
}
console.log(increment);
}
disbaleDate();
const disable = () => {
const arr = [
"1/6/2022",
"12/6/2022",
"4/6/2022",
"6/6/2022",
"1/6/2022",
"1/6/2022",
];
let data =[];
data = arr.filter((el, i) => i !== arr.indexOf(el) )
let result = data.filter((el,i) => i ===data.indexOf(el))
return result;
}
console.log(disable())
Ok, updating my answer
// reducer willproduce an object with the date as the key, and the amount repeated as the value
const countRepeated = arr.reduce((a, c) => {
if (a[c]) {
a[c] = a[c] + 1;
return a;
}
a[c] = 1;
return a;
}, {})
// will filter those whose values are greater than 2
return Object.keys(countRepeated).filter( date => date > 2)
function disableDate() {
const arr = ["1/6/2022", "12/6/2022", "4/6/2022", "6/6/2022", "1/6/2022", "1/6/2022",];
const backendData = ["12/12/2022", "12/6/2021", "14/6/2022", "16/6/2022", "1/6/2022", "11/6/2022",];
const increment = [];
if (backendData.length > 0) {
for (let i = 0; i < backendData.length; i++) {
if (arr.includes(backendData[i])) {
increment.push(backendData[i]);
}
}
}
console.log(increment);
}
disableDate();

JavaScript array or object checking - code improvements

I receive data => these data could be array of object or just a object.
I write some code, but maybe there is a way to make this code more sexy, clear, or shorter plus without any errors
Here is the code:
export const CalculateIt = (props) => {
const conversionValues = []
if (props) {
if (props.length > 0) {
for (let i = 0; i < props.length; i++) {
const clicks = props[i]?.insights?.[0].inline_link_clicks
const actionsNumber = props[i]?.insights?.[0]?.actions?.length || 0
let result = 0
if (clicks && actionsNumber) {
result = devideNumbers(clicks, actionsNumber, 8)
}
conversionValues.push(result)
}
return conversionValues
}
const clicks = props?.insights?.[0].inline_link_clicks
const actionsNumber = props?.insights?.[0]?.actions?.length || 0
let result = 0
if (clicks && actionsNumber) {
result = devideNumbers(clicks, actionsNumber)
}
return conversionValues.push(result)
}
}
As you can see there you can find some parts of the code that are similar like:
const clicks = props[i]?.insights?.[0].inline_link_clicks
and
const clicks = props?.insights?.[0].inline_link_clicks
Is it possible to write it more smart?
Best
Probably move the common code in a function:
function getResult(data) {
const clicks = data?.insights?.[0].inline_link_clicks
const actionsNumber = data?.insights?.[0]?.actions?.length || 0
let result = 0
if (clicks && actionsNumber) {
result = devideNumbers(clicks, actionsNumber, 8)
}
return result;
}
And use the helper function in your original function:
export const CalculateIt = (props) => {
const conversionValues = []
if (props) {
if (props.constructor === Array) {
props.forEach((item) => conversionValues.push(getResult(item)))
} else {
conversionValues.push(getResult(props));
}
return conversionValues;
}
}
In fact, you can force all data into a one-dimensional array and safe work with array of objects only.
Is this code sexy enough?
const obj = {id: 1, val: 1};
const arr = [{id: 1, val: 1},{id: 2, val: 2},{id: 3, val: 3}];
const normalize = (data) => [data].flat();
console.log(normalize(obj)[0]);
console.log(normalize(arr)[0]);
// -------------------
// and you can use this approach in code:
const getResult = (obj) => obj.val * 10;
const CalculateIt = (props) => [props].flat().map(getResult);
console.log(CalculateIt(obj));
console.log(CalculateIt(arr));
.as-console-wrapper{min-height: 100%!important; top: 0}

How can I find the index of a 2d array of objects in javascript

So, what I'm trying to get is the index of a 2d array of objects, let's say I have the following
const arr = [
[{id: 1}, {id:2}],
[{id:3},{id:4},{id:5}]
]
If I'd want to get the index where id=3 it would be arr[1][0], Is there any way to achieve this using vanilla JS or any helper library?
You can achieve this by nesting two for loops.
function findNestedIndices(array, id) {
let i;
let j;
for (i = 0; i < array.length; ++i) {
const nestedArray = array[i];
for (j = 0; j < nestedArray.length; ++j) {
const object = nestedArray[j];
if (object.id === id) {
return { i, j };
}
}
}
return {};
}
const array = [
[{id: 1}, {id:2}],
[{id:3},{id:4},{id:5}]
];
const { i, j } = findNestedIndices(array, 3);
console.log(i, j); // 1, 0
Might be a more efficient way to do it, but you could accomplish this via array.findIndex:
const test = [
[{id: 1}, {id:2}],
[{id:3},{id:4},{id:5}]
];
function find(arr, id) {
const firstIndex = arr.findIndex(entry => entry.some(({id: x}) => x === id));
if (firstIndex > -1) {
const secondIndex = arr[firstIndex].findIndex(({ id: x }) => x === id );
return [firstIndex, secondIndex];
}
}
console.log(find(test, 2)); // [0, 1]
console.log(find(test, 4)); // [1, 1]
console.log(find(test, 5)); // [1, 2]
const arr = [
[{id: 1}, {id:2}],
[{id:3},{id:4},{id:5}]
];
let searchIndex = 3;
let x = arr.findIndex(sub => sub.find(el => el.id == searchIndex));
let y = arr[x].findIndex(el => el.id == searchIndex);
console.log(x, y)
const arr = [
[{id: 1}, {id:2}],
[{id:3},{id:4},{id:5}]
];
function getIndex(arr, value){
let rowIndex = null;
let valueIndex = null;
arr.forEach(( nestedArray, index) => {
if(!valueIndex) rowIndex = index;
nestedArray.every((val, valIndex) => {
if(val.id === value) {
valueIndex = valIndex;
return false
}
return true;
});
})
return {
rowIndex,
valueIndex
}
}
console.log(getIndex(arr, 3))

How to remove same value if it has in an array? [duplicate]

Let's assume that I have ;
var array = [1,2,3,4,4,5,5];
I want it to be;
var newArray = [1,2,3];
I want to remove the duplicates completely rather than keeping them as unique values. Is there a way achieve that through reduce method ?
You could use Array#filter with Array#indexOf and Array#lastIndexOf and return only the values which share the same index.
var array = [1, 2, 3, 4, 4, 5, 5],
result = array.filter(function (v, _, a) {
return a.indexOf(v) === a.lastIndexOf(v);
});
console.log(result);
Another approach by taking a Map and set the value to false, if a key has been seen before. Then filter the array by taking the value of the map.
var array = [1, 2, 3, 4, 4, 5, 5],
result = array.filter(
Map.prototype.get,
array.reduce((m, v) => m.set(v, !m.has(v)), new Map)
);
console.log(result);
I guess it won't have some remarkable performance, but I like the idea.
var array = [1,2,3,4,4,5,5],
res = array.reduce(function(s,a) {
if (array.filter(v => v !== a).length == array.length-1) {
s.push(a);
}
return s;
}, []);
console.log(res);
Another option is to use an object to track how many times an element is used. This will destroy the array order, but it should be much faster on very large arrays.
function nukeDuplications(arr) {
const hash = {};
arr.forEach(el => {
const qty = hash[el] || 0;
hash[el] = qty+1;
});
const ret = [];
Object.keys(hash).forEach(key => {
if (hash[key] === 1) {
ret.push(Number(key));
}
})
return ret;
}
var array = [1,2,3,4,4,5,5];
console.log(nukeDuplications(array));
A slightly more efficient solution would be to loop over the array 1 time and count the number of occurrences in each value and store them in an object using .reduce() and then loop over the array again with .filter() to only return items that occurred 1 time.
This method will also preserve the order of the array, as it merely uses the object keys as references - it does not iterate over them.
var array = [1,2,3,4,4,5,5];
var valueCounts = array.reduce((result, item) => {
if (!result[item]) {
result[item] = 0;
}
result[item]++;
return result;
}, {});
var unique = array.filter(function (elem) {
return !valueCounts[elem] || valueCounts[elem] <= 1;
});
console.log(unique)
Another option is to use an object to track how many times an element is used. This will destroy the array order, but it should be much faster on very large arrays.
// Both versions destroy array order.
// ES6 version
function nukeDuplications(arr) {
"use strict";
const hash = {};
arr.forEach(el => {
const qty = hash[el] || 0;
hash[el] = qty + 1;
});
const ret = [];
Object.keys(hash).forEach(key => {
if (hash[key] === 1) {
ret.push(Number(key));
}
})
return ret;
}
// ES5 version
function nukeDuplicationsEs5(arr) {
"use strict";
var hash = {};
for (var i = 0; i < arr.length; i++) {
var el = arr[i];
var qty = hash[el] || 0;
hash[el] = qty + 1;
};
var ret = [];
for (let key in hash) {
if (hash.hasOwnProperty(key)) {
if (hash[key] === 1) {
ret.push(Number(key));
}
}
}
return ret;
}
var array = [1, 2, 3, 4, 4, 5, 5];
console.log(nukeDuplications(array));
console.log(nukeDuplicationsEs5(array));
There are a lot of over-complicated, and slow running code here. Here's my solution:
let numbers = [1,2,3,4,4,4,4,5,5]
let filtered = []
numbers.map((n) => {
if(numbers.indexOf(n) === numbers.lastIndexOf(n)) // If only 1 instance of n
filtered.push(n)
})
console.log(filtered)
you can use this function:
function isUniqueInArray(array, value) {
let counter = 0;
for (let index = 0; index < array.length; index++) {
if (array[index] === value) {
counter++;
}
}
if (counter === 0) {
return null;
}
return counter === 1 ? true : false;
}
const array = [1,2,3,4,4,5,5];
let uniqueValues = [];
array.forEach(element => {
if(isUniqueInArray(array ,element)){
uniqueValues.push(element);
}
});
console.log(`the unique values is ${uniqueValues}`);
If its help you, you can install the isUniqueInArray function from my package https://www.npmjs.com/package/jotils or directly from bit https://bit.dev/joshk/jotils/is-unique-in-array.
My answer is used map and filter as below:
x = [1,2,3,4,2,3]
x.map(d => x.filter(i => i == d).length < 2 ? d : null).filter(d => d != null)
// [1, 4]
Object.values is supported since ES2017 (Needless to say - not on IE).
The accumulator is an object for which each key is a value, so duplicates are removed as they override the same key.
However, this solution can be risky with misbehaving values (null, undefined etc.), but maybe useful for real life scenarios.
let NukeDeps = (arr) => {
return Object.values(arr.reduce((curr, i) => {
curr[i] = i;
return curr;
}, {}))
}
I would like to answer my questions with an answer I came up with upon reading it again
const array = [1, 2, 3, 4, 4, 5, 5];
const filtered = array.filter(item => {
const { length } = array.filter(currentItem => currentItem === item)
if (length === 1) {
return true;
}
});
console.log(filtered)
//Try with this code
var arr = [1,2, 3,3,4,5,5,5,6,6];
arr = arr.filter( function( item, index, inputArray ) {
return inputArray.indexOf(item) == index;
});
Also look into this link https://fiddle.jshell.net/5hshjxvr/

JavaScript dual recursive call, how to pass back result?

I have one piece of JavaScript code which call recursive method twice, the result couldn't pass back:
var subSum = (nums, target) => {
var res = [];
var chosen = [];
subSets(nums, chosen, target, res);
return res;
};
var subSets = (nums, chosen, target, res) => {
if (nums.length === 0) {
if (sumAry(chosen) == target) {
console.log(array2Str(chosen));
res.push(chosen);
}
//console.log(array2Str(chosen));
} else {
let it = nums[0];
nums.shift();
chosen.push(it);
subSets(nums, chosen, target, res);
chosen.pop();
subSets(nums, chosen, target, res);
nums.unshift(it);
}
};
var array2Str = (ary) => {
if (!ary || ary.length < 1) return '';
let res = [];
arrayToStr(ary, res);
return res.join("");
};
var arrayToStr = (ary, res) => {
res.push('[');
for(let i = 0; i < ary.length; i ++) {
let it = ary[i];
if (Array.isArray(it)) {
arrayToStr(it, res);
if (i != ary.length - 1) {
res.push(', ');
}
} else {
res.push( (i == ary.length - 1) ? `${it}` : `${it}, `);
}
}
res.push(']');
};
The test code is:
let nums = [5,3,1,2,4,6];
console.log(`array2Str(subSum(nums, 7))`);
The output is:
Debugger attached.
[5, 2]
[3, 4]
[1, 2, 4]
[1, 6]
[[], [], [], []]
You can see the last line is the dump of the result array (res), and the content of 4 sub array are empty, but according the console log above, those values were pushed into the result array. anyway, if I comment out last subSets recursive call, the final result printing will not be empty.
Any idea on how to pass back the result with two recursive call? I tried one global array container and it didn't either.
the array is passing by reference , that's way is being overwriting .
use a primitive type like string , or shallow copy chosen array .
for this change the push line to this
res.push(chosen.slice()) // for shllow copy
res.push(chosen.join()) // for using primitive string
// i assume that the missing sumAry function shuld do ..
const sumAry = array => array.reduce((a, b) => a + b, 0)
var subSum = (nums, target) => {
var res = []
var chosen = []
subSets(nums, chosen, target, res)
return res
}
var subSets = (nums, chosen, target, res) => {
if (nums.length === 0) {
if (sumAry(chosen) == target) {
console.log(array2Str(chosen))
res.push(chosen.slice())
// res.push(chosen.join())
}
} else {
let it = nums[0]
nums.shift()
chosen.push(it)
subSets(nums, chosen, target, res)
chosen.pop()
subSets(nums, chosen, target, res)
nums.unshift(it)
}
}
var array2Str = ary => {
if (!ary || ary.length < 1) return ''
let res = []
arrayToStr(ary, res)
return res.join('')
}
var arrayToStr = (ary, res) => {
res.push('[')
for (let i = 0; i < ary.length; i++) {
let it = ary[i]
if (Array.isArray(it)) {
arrayToStr(it, res)
if (i != ary.length - 1) {
res.push(', ')
}
} else {
res.push(i == ary.length - 1 ? `${it}` : `${it}, `)
}
}
res.push(']')
}
let nums = [5, 3, 1, 2, 4, 6]
console.log(array2Str(subSum(nums, 7)))

Categories

Resources