Unexpected results from array.map() - javascript

Very simple question but I couldn't figure why the below code results in NaN in first index?
var arr = [1, 2, 3, 4];
var result = arr.map(function(x) {
if(arr[x] >= 2) {
return arr[x] + 10;
} else {
return arr[x] - 10;
}
});
console.log(result); // [-9, 12, 13, NaN]

Array map accepts parameter as (item,index). In your case x is representing array element which will be 1,2,3,4 and so on. So arr[1] will be first element that is 1, but arr[4] will be undefined since there is no element present at the fifth index. You can replace arr[x] with only x or with arr[index]
var arr = [1, 2, 3, 4];
var result = arr.map(function(x, index) {
console.log('Array element', x)
if (arr[index] >= 2) {
return arr[index] + 10;
} else {
return arr[index] - 10;
}
});
console.log(result);

The first argument of the callback is set to the element of the array
var arr = [1, 2, 3, 4];
var result = arr.map(function(x) {
if(x >= 2) {
return x + 10;
} else {
return x - 10;
}
});
console.log(result)

If you want to use the index, then in map it is second parameter. The first parameter is the array element.
var arr = [1, 2, 3, 4];
var result = arr.map(function(x, i) {
if(arr[i] >= 2) {
return arr[i] + 10;
} else {
return arr[i] - 10;
}
});
console.log(result); // [12, 13, 14, NaN]
But, there is no necessity of index to access the array element.
var arr = [1, 2, 3, 4];
var result = arr.map(function(x, i) {
if(x >= 2) {
return x + 10;
} else {
return x - 10;
}
});
console.log(result); // [12, 13, 14, NaN]

js map function iterate the elements (in your case) not the indexes. Your x varriable is the current element in iteration
var arr = [1, 2, 3, 4];
var result = arr.map(function(x) {
if(x >= 2) {
return x + 10;
} else {
return x - 10;
}
});
console.log(result);

var arr = [1, 2, 3, 4];
var result = arr.map(function(val, indx) {
if(arr[indx] >= 2) {
return arr[indx] + 10;
} else {
return arr[indx] - 10;
}
});
You need to use index not value
or you can do it like a pro
const result = arr.map((val, indx) => {
return (val >= 2) ? val+10 : val -10
});

x in your code is actually referencing an item of your array, not an index.
You can re-write your code as follows:
var arr = [1, 2, 3, 4]
var result = arr.map( x => (x >= 2) ? x+10 : x-10 )
console.log(result) // [-9, 12, 13, 14]

Related

Find duplicate pairs in an array

I have an array a = [1,1,1,2,2,3,3,3,4,4,4,6,6,6,7,7]
I want to fetch all the duplicate pair in this array list.
Since there are pairs of 2 and 7 the output should be -
Output: [2, 7]
I tried writing my own logic but I am very weak in that area. Can somebody help?
function getDuplicateArrayElements(arr){
let sorted_arr = arr.slice().sort();
let results = [];
for (let i = 0; i < sorted_arr.length; i++) {
let matchingElementCount = 1;
for (let j = i + 1; j < sorted_arr.length - i; j++) {
if (sorted_arr[j] === sorted_arr[i]) {
++matchingElementCount;
} else {
if(matchingElementCount % 2 === 0) {
results.push(sorted_arr[i]);
}
i = j - 1;
break;
}
}
}
return results; } var a = [1,1,1,2,2,3,3,3,4,6,6,6,7,7]; var duplicateValues= getDuplicateArrayElements(a);
You can achieve your result by using reduce and forEach.
const arr = [1,1,1,1,2,2,3,3,3,4,4,4,6,6,6,7,7];
// Generate a hashmap from the given array for counting the frequency.
const hashMap = arr.reduce((a, c) => {
a[c] = (a[c] || 0) + 1;
return a;
}, {});
const pair = [];
// If the frequency is divided by 2 then push the key of the hashMap into pair array.
Object.entries(hashMap).forEach(([k, v]) => {
if (v % 2 === 0) {
[...Array(Math.floor(v / 2))].forEach(_ => pair.push(k));
}
})
console.log(pair);
You can grab the frequency of each number, and then filter out any which have an odd frequency. You can then .flatMap() the frequencies to an array containing your number for each pair you found like so:
const a = [1,1,1,2,2,3,3,3,4,4,4,6,6,6,7,7];
const freq = a.reduce((m, n) => m.set(n, (m.get(n) || 0) + 1), new Map);
const res = [...freq].filter(([n, count]) => count % 2 == 0).flatMap(([n, c]) => Array(c/2).fill(n));
console.log(res);
This way, if you have four 1s (ie: two pairs of 1s), the filter will pick up on that, allowing you to flat-map the [1, 4] array to an array of [1, 1], which is merged into the larger resulting array.
You could create a helper map and keep the counts of each number as the values and the numbers itself as the keys. After iterating through the array, you only need to find the ones with a count divisible by 2:
var a = [1, 1, 1, 2, 2, 3, 3, 3, 4, 6, 6, 6, 7, 7]
function findDuplicates(arr) {
const map = {};
for (const curr of arr) {
if (!map[curr]) {
map[curr] = 0;
}
map[curr]++;
}
const res = [];
for (const key in map) {
if (map.hasOwnProperty(key) && map[key] % 2 === 0) {
res.push(Number.parseInt(key));
}
}
return res;
}
console.log(findDuplicates(a));
You can first count the occurrence of each numbers and if it is greater than 0 and divisible by 2 then add these to final result else don't
function getDuplicateArrayElements(arr) {
let map = {}
let results = [];
for (let num of arr) {
map[num] = map[num] || 0
map[num]++
}
return Object.keys(map)
.filter(v => map[v] && map[v] % 2 === 0)
.map(v => new Array(map[v]/2).fill(+v))
.flat()
.sort()
}
var a = [1, 1, 1, 2, 2, 3, 3, 3, 4, 6, 6, 6, 7, 7,8,8,8,8];
var duplicateValues = getDuplicateArrayElements(a);
console.log(duplicateValues)
const a = {};
[1,1,1,2,2,3,3,3,4,6,6,6,7,7].forEach(v => {a[v] = a[v] ? a[v] + 1 : 1});
const l = [];
Object.keys(a).forEach(k => !(a[k] % 2) && l.push(k));
Here you go:
function getDuplicateArrayElements(arr){
var dupilcates=arr.filter(x => arr.filter(y=>y==x).length==2);
var found=[];
for(var i=0;i<dupilcates.length;i=i+2)
found.push(dupilcates[i]);
return found;
}
This will give you the desired pairs. with [1, 1, 1, 1, 2, 2, 3, 3, 3, 4, 6, 6, 6, 6, 7, 7] input it will return [1,1,2,6,6,7]:
function getDuplicateArrayElements(arr){
let sorted_arr = arr.slice().sort();
let results = [];
let i = 0;
while (i < sorted_arr.length) {
let counter = 1;
let j = i;
while (sorted_arr[j] === sorted_arr[j+1]) {
counter++;
j++;
}
if (counter%2 == 0) {
results.push(...Array(counter/2).fill(sorted_arr[i]))
}
i += counter;
}
return results;
}
var a = [1, 1, 1, 1, 2, 2, 3, 3, 3, 4, 6, 6, 6, 6, 7, 7];
console.log(getDuplicateArrayElements(a));
Another rather concise solution:
a = [1,1,1,2,2,3,3,3,4,4,4,6,6,6,7,7];
uniques = new Set(a); //filter out duplicates
res = [];
uniques.forEach((key)=>{
if(a.filter(elem => elem === key).length === 2){res.push(key)};
//filter out only the elements which match the key being tested
//if there are 2, push to result
})
Edit: even more concise, but perhaps less efficient:
a = [1,1,1,2,2,3,3,3,4,4,4,6,6,6,7,7];
res = Array.from(new Set(a.filter(elem => a.filter(el => el === elem).length === 2)));
Javascript has awesome JSON object, in my opinion, you can use json as a dictionary;
{ key: _value }.
Loop throw array one times, no sort, no slice
key is array's element value, _value is frequency
var frequencies = {};
for (let i = 0; i < a.length; a++) {
if (result[a[i]] == 'over') continue;
if (result[a[i]] == undefined) { // First times
result[a[i]] = 1
} else if (result[a[i]] == 1) { // Second times
result[a[i]] = 2
} else { // Ignore if > 2
result[a[i]] = 'over'
}
}
// result: {1: "over", 2: 2, 3: "over", 4: "over", 6: "over", 7: 2}
so now pick keys have value equal 2
function getDuplicateArrayElements(numbers: number[]): number[] {
const occurences = new Map<number, number>();
for (let number of numbers) {
if (occurences.has(number)) {
const current = occurences.get(number)!;
occurences.set(number, current + 1);
} else
occurences.set(number, 1)
}
return (
Array
.from(occurences.entries())
.reduce<number[]>(
(accumulator, [key, value]) => {
if (value === 2) {
return accumulator.concat(key)
}
return accumulator
},
[]
)
)
}
const a = [1, 1, 1, 2, 2, 3, 3, 3, 4, 4, 4, 6, 6, 6, 7, 7];
getDuplicateArrayElements(a); // [2, 7]

Getting Values from array - Javascript

Trying my best, but still not able to log the result at the end.
var arr = [2, 2, 2, 2, 2, 4, 5, 5, 5, 9];
function foo(arr) {
var a = [], b = [], prev;
arr.sort();
for ( var i = 0; i < arr.length; i++ ) {
if ( arr[i] !== prev ) {
a.push(arr[i]);
b.push(1);
} else {
b[b.length-1]++;
}
prev = arr[i];
}
return [a, b];
}
var result = foo(arr);
var a = result[0]
var b = result[1]
var aa=a.split(",");
var ab=b.split(",");
var a = a.split(",").length;
var b = b.split(",").length;
for (c = 0; c < a; c++){
console.log(aa[c]);
console.log(ab[c]);}
I want to get values from two array result[0] and result[1] one by one in the loop.
Right now I am able to get all the values comma separated but when I split values, nothing shows up.
You were almost there:
var arr = [2, 2, 2, 2, 2, 4, 5, 5, 5, 9];
function foo(arr) {
var a = [], b = [], prev;
arr.sort();
for ( var i = 0; i < arr.length; i++ ) {
if ( arr[i] !== prev ) {
a.push(arr[i]);
b.push(1);
} else {
b[b.length-1]++;
}
prev = arr[i];
}
return [a, b];
}
var result = foo(arr);
var a = result[0]
var b = result[1]
for (i=0; i<a.length; i++){
console.log("Number: " + a[i] + "; Time repeated:"+ b[i]); }
You can create an empty object to track the number of repetitions & an array to hold only unique values.Use indexOf to find if element already exist in uniqArray.
var arr = [2, 2, 2, 2, 2, 4, 5, 5, 5, 9];
var repCount = {}, // to track number of repetitions
uniqArray = []; // holds only unique values
arr.forEach(function(item) {
if (uniqArray.indexOf(item) == -1) {
// id item is not present push it
uniqArray.push(item)
}
// check if the object already have a key for example 2,4,5,9
if (!repCount.hasOwnProperty(item)) {
repCount[item] = 1 // if not then create new key
} else {
// if it is there then increase the count
repCount[item] = repCount[item] + 1
}
})
console.log(uniqArray, repCount)
Looking at your comment...
So basically i want to get the unique no. from array and the no. of repetition of that particular value into another variable
You can achieve this by using reduce function
var arr = [2, 2, 2, 2, 2, 4, 5, 5, 5, 9];
var a = arr.reduce(function (acc, next) {
acc[next] = acc[next] ? acc[next] + 1 : 1;
return acc;
}, {});
console.log(a);
which gives you a hash with unique numbers as keys and their counts as values. From here you can easily break it into two arrays if you really need to..

Finding chained, incremented values in array

I'm trying to find all values in an array that would form a chain of incremented values - all referencing back to a certain starting value. Increments can go both "up" and "down".
array = [10, 2, 3, 5, 9, 11]
Starting with the number 2 should return:
[2, 3]
Starting with the number 10 should return:
[9, 10, 11]
There are of course plenty of inefficient ways of doing this, but I'm asking this here because doing this efficiently is important for my case and I'm such a JS newbie.
You can use Array.prototype.includes() to check if a number exists in an array. If the number is before the base reference add it using unshift, if after add it using push:
var array = [10, 2, 3, 5, 9, 11];
function findChain(array, num) {
if(!array.includes(num)) {
return [];
}
const result = [num];
let before = num - 1;
let after = num + 1;
while(array.includes(before)) {
result.unshift(before--);
}
while(array.includes(after)) {
result.push(after++);
}
return result;
}
console.log('Ref 2 -', findChain(array, 2));
console.log('Ref 5 -', findChain(array, 5));
console.log('Ref 10 -', findChain(array, 10));
console.log('Ref 20 -', findChain(array, 20));
A quick solution :
var array = [10, 2, 3, 5, 9, 11, 14, 89, 12, 8];
var trouver = nombre => {
var result = [];
if (array.indexOf(nombre) !== -1) result.push(nombre);
else return result;
for(var chiffre = nombre+1; array.indexOf(chiffre) !== -1; chiffre++) result.push(chiffre);
for(var chiffre = nombre-1; array.indexOf(chiffre) !== -1; chiffre--) result.push(chiffre);
return result.sort((a,b) => a-b);
}
console.log(trouver(9)); //[ 8, 9, 10, 11, 12 ]
Another solution could be a double chained list for it.
function getValues(array, value) {
var object = Object.create(null),
result,
o;
array.forEach(function (a) {
object[a] = object[a] || { value: a, pre: object[a - 1] || null, succ: object[a + 1] || null };
if (object[a - 1]) {
object[a - 1].succ = object[a];
}
if (object[a + 1]) {
object[a + 1].pre = object[a];
}
});
o = object[value];
if (o) {
result = [];
while (o.pre) {
o = o.pre;
}
while (o.succ) {
result.push(o.value);
o = o.succ;
}
result.push(o.value);
}
return result;
}
var array = [10, 2, 3, 5, 9, 11, 14, 89, 12, 8];
console.log(getValues(array, 2));
console.log(getValues(array, 10));
console.log(getValues(array, 42));
.as-console-wrapper { max-height: 100% !important; top: 0; }
Try this approach
Sort the array first
Iterate array items one by one, keep pushing the start-counter if current-item value is not bigger than last-item by 1, else reset the start-counter to current-index.
For Example :
var arr = [10, 2, 3, 5, 9, 11];
function getAllSequences(arr) {
arr.sort(function(a, b) {
return a - b
});
var startIndex = 0;
var endIndex = 0;
var lastItem = 0;
var chains = [];
arr.forEach(function(item, index) {
if (index > 0) {
if ((item - lastItem) > 1) {
extractChain(chains, arr, startIndex, endIndex);
startIndex = index;
} else {
endIndex = index;
if (index == arr.length - 1) {
extractChain(chains, arr, startIndex, endIndex);
}
}
}
lastItem = item;
});
return chains;
}
console.log(getAllSequences(arr));
function extractChain(chains, arr, startIndex, endIndex) {
var value = arr.slice(startIndex, endIndex + 1);
if (value.length > 0) {
chains.push(value);
}
}

Lodash swap adjacent items if condition is met

Say I have an array, [1, 2, 3, 4, 5, 3, 4, 6, 3, 7, 4]. I want to swap the values of 3 and 4 iff they are adjacent an in the order [3, 4] (i.e. [4, 3] remain intact). The result of the example would be [1, 2, 4, 3, 5, 4, 3, 6, 3, 7, 4].
Is there an elegant way to do this in Lodash without the use of for loops?
Edit:
How about
_.sortBy(arr, function(value, index) {
if (value === 3) {
return index + 0.75;
} else if (value === 4) {
return index - 0.75;
} else {
return index
}
});
Edit 2:
Went with the following (it's not actually 3 and 4).
return _.reduce(tags, function(out, tag) {
var word = tag[0];
if (out[0] && unitPowerSuffixes.hasOwnProperty(word)) {
out.splice(-1, 0, {
type: 'unit-power',
value: unitPowerSuffixes[word]
}); // Insert one from end
} else {
out.push(tag);
}
return out;
}, []);
Is there an elegant way to do this in Lodash without the use of for loops?
Yes, you can use reduce as follows:
var array = [1, 2, 3, 4, 5, 3, 4, 6, 3, 7, 4];
var result = _.reduce(array, swapAdjacentInOrder(3, 4), []);
alert(JSON.stringify(result));
function swapAdjacentInOrder(a, b) {
return function (result, element) {
var length = result.length;
if (length > 0 && element === b) {
var last = length - 1;
if (result[last] === a) {
result[last] = b;
element = a;
}
}
result[length] = element;
return result;
};
}
<script src="https://rawgit.com/lodash/lodash/master/lodash.min.js"></script>
However, the swapAdjacentInOrder function also has the following property:
var array = [3, 4, 4, 4];
var result = _.reduce(array, swapAdjacentInOrder(3, 4), []);
alert(JSON.stringify(result)); // [4, 4, 4, 3]
function swapAdjacentInOrder(a, b) {
return function (result, element) {
var length = result.length;
if (length > 0 && element === b) {
var last = length - 1;
if (result[last] === a) {
result[last] = b;
element = a;
}
}
result[length] = element;
return result;
};
}
<script src="https://rawgit.com/lodash/lodash/master/lodash.min.js"></script>
If you don't want that then you can do the following updated swapAdjacentInOrder function:
var array = [3, 4, 4, 4];
var result = _.reduce(array, swapAdjacentInOrder(3, 4), []);
alert(JSON.stringify(result)); // [4, 3, 4, 4]
function swapAdjacentInOrder(a, b) {
return function (result, element) {
var length = result.length;
if (length > 0 && element === b) {
var last = length - 1;
if (result[last] !== a || last > 0 && result[last - 1] === b);
else {
result[last] = b;
element = a;
}
}
result[length] = element;
return result;
};
}
<script src="https://rawgit.com/lodash/lodash/master/lodash.min.js"></script>
Hope that helps.
A really functional way would be to use something like splitOn. But we can do that using strings (not even needing lodash):
arr.join().split("3,4").join("4,3").split(",").map(Number)

Why doesn't this recursive javascript function return the correct value

Why does this function return undefined?
The interior function returns the correct value.
function arraySum(i) {
// i will be an array, containing integers, strings and/or arrays like itself.
// Sum all the integers you find, anywhere in the nest of arrays.
(function (s, y) {
if (!y || y.length < 1) {
//console.log(s);
// s is the correct value
return s;
} else {
arguments.callee(s + y[0], y.slice(1));
}
})(0, i);
}
var x = [1, 2, 3, 4, 5];
arraySum(x);
Change it to
return arguments.callee( s + y[0], y.slice(1))
Or just use reduce :-) :
[1,2,3,4].reduce( function(sum, x) { return sum + x; }, 0 );
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce
If what you said in the code's comment is true, this is what you need.
function arraySum(i) {
// i will be an array, containing integers, strings and/or arrays like itself
// Sum all the integers you find, anywhere in the nest of arrays.
return (function (s, y) {
if (y instanceof Array && y.length !== 0) {
return arguments.callee(arguments.callee(s, y[0]), y.slice(1));
} else if (typeof y === 'number') {
return s + y;
} else {
return s;
}
})(0, i);
}
Output
var x = [1, 2, 3, 4, 5];
console.log(arraySum(x));
x = [1, 2, [3, 4, 5]];
console.log(arraySum(x));
x = [1, "2", 2, [3, 4, 5]];
console.log(arraySum(x));
x = [1, "2", [2, [3, 4, 5]]];
console.log(arraySum(x));

Categories