How do I succinctly write a function such that it creates a new array of object using every pair of elements from an array?
Assume even number of elements.
Example input:
input = [1, 42, 55, 20, 3, 21]
Output:
output = [{x:1, y:42}, {x:55, y:20}, {x:3, y:21}]
Edit:
This is the current solution I have which I am not a fan of:
[1, 42, 55, 20, 3, 21].reduce(
(acc, curr, i) => (
i % 2 === 0
? [...acc, { x: curr }]
: [...acc.slice(0, -1), { x: acc[acc.length - 1].x, y: curr }]), []
)
You can use a for loop which increment by the value of 2
const input = [1, 42, 55, 20, 3, 21];
const res = [];
for(let i = 0; i < input.length; i+=2){
res.push({x:input[i], y: input[i + 1]});
}
console.log(res)
I think breaking it into two steps helps with readability but it is marginally less efficient.
[1,42,55,20,3,21]
.map((n, i, arr) => ({ x: n, y: arr[i + 1] }))
.filter((n, i) => i % 2 === 0);
You can just iterate the array. For odd length last value won't be paired, since no pair is available
const array = [1, 42, 55, 20, 3, 21];
var output = [];
for (index = 0; index < array.length-1; index+=2) {
output.push({x:array[index], y:+array[index+1]});
}
console.log(output);
I think a simplification of your technique is readable enough:
const toPoints = coordinates =>
coordinates .reduce (
(acc, curr, i, all) => (i % 2 === 0 ? acc : [...acc, { x: all[i - 1], y: curr }]),
[]
)
console .log (toPoints ([1, 42, 55, 20, 3, 21]))
We simply add the next pair only on the even indices. Of course this will fail if you want an odd-length array to end up with a final object with an x- but not a y- property.
An approach which has benefit of being easy to reason about:
const arr = [1,42,55,20,3,21];
const pairs = [...Array(arr.length/2).keys()].map(c => ({x: arr[2*c], y: arr[2*c + 1]}));
Related
I want to remove values in a range from an array. For example, removeVals([20, 30, 40, 50, 60, 70], 2, 4) should return the array [20, 30, 70]. How can I solve this problem?
This can be done in one-liner. If you're unfamiliar with arrow functions this might be a bit confusing but I'll put my solution out there anyway.
var removeVals = (array, start, end) => array.filter((item, index) => index < start || index > end);
console.log(removeVals([20, 30, 40, 50, 60, 70], 2, 4)) // [20, 30, 70]
JavaScript's built-in filter function iterates through an array, and passes each item (and the index of said item optionally) into the function that it's provided. If the return value of that function is true, then the item stays in the array, otherwise it is removed. The function that we pass into the filter function only returns true if the index of the current item in the array is less than the beginning of the range or more that the end of the range, therefore removing items that are in the range.
You can use Array#splice, which changes the input array. So you would need to return the modified array.
DEMO
const removeVals = (arr, start, end) => arr.splice(start, end-start+1) && arr;
console.log( removeVals([20, 30, 40, 50, 60, 70], 2, 4) );
This solution works like .filter() demonstrated in tybocopperkettle's answer, but with .flatMap() instead. Using a ternary in .flatMap() gives us an advantage of returning almost any value.
idx < a || idx > z ? num : []
JavaScript
Description
idx < a
If index is less than start...
||
...OR...
idx > z
...if index is greater than end...
? num
...return the value...
:[]
...otherwise return nothing🞾
🞾[] returns as nothing since .flatMap() applies .flat() to whatever it returns.
const arrayA = [20, 30, 40, 50, 60, 70];
const Aa = 2;
const Az = 4;
const arrayB = ['A', 'B', 'C', 'D', 'E', 'F'];
const Ba = 0;
const Bz = 7;
const remVal = (array, a, z) => array
.flatMap((num, idx) =>
idx < a || idx > z ?
num : []
);
console.log(remVal(arrayA, Aa, Az));
console.log(remVal(arrayB, Ba, Bz));
Method-1
This method removes the subset in the range Array[startIx, stopIx] from the source array using the Array.prototype.splice()method.
// INPUT → array[0, array.length - 1]
// OUTPUT → array[0, startIx - 1] U array[stopIx + 1, array.length - 1]
let removeVals = (array, startIx, stopIx) => {
array.splice(startIx, stopIx - startIx + 1);
return array;
}
let array= [20, 30, 40, 50, 60, 70]
console.log(`Result: ${removeVals(array, 2, 4)}`);
Method-2
Create a new array inside the function.
Add the values in the range array[0, startIx - 1] to the new array.
Add values from range array[stopIx+ 1, array.lenght - 1] to the new array.
// INPUT → array[0, array.length - 1]
// OUTPUT → array[0, startIx - 1] U array[stopIx + 1, array.length - 1]
let removeVals = (array, startIx, stopIx) => {
let resultArray = []
for(let i = 0; i < startIx ; ++i)
resultArray.push(array[i])
for(let i = stopIx + 1 ; i < array.length ; ++i)
resultArray.push(array[i])
return resultArray;
}
let array= [20, 30, 40, 50, 60, 70]
console.log(`Result: ${removeVals(array, 2, 4)}`);
I am certain my issue here is not knowing what to call what I'm trying to do here, so any help with that would be appreciated, but I'd like to map over an array and create two values, where the first one refers to the prior value... is that possible?
arr =[1,2,3]
arr.map((el, i) => ({
x: el,
y: 5,
z: y[i] + 2 // is there a way I can write this so I can refer to y ???
}))
any help appreciated!
Is this what you're looking for?
const arr = [1, 2, 3]
const newArr = arr.map((currentValue, currentIndex) => {
const previousValue = currentIndex > 0 ? arr[currentIndex - 1] : 0
const output = {
x: currentValue,
y: 5,
z: previousValue + 2
}
return output
})
I'm still a junior at web dev and I am trying to solve this problem.
I have to find the number of matching pairs in these arrays:
var ar1 = [10, 20, 20, 10, 10, 30, 50, 10, 20] // return 3 (2 pairs of 10 and 1 pair of 20)
var ar2 = [1, 1, 3, 1, 2, 1, 3, 3, 3, 3] // return 4 (2 pairs of 1 and 2 pairs of 3)
// I started to write my logic below but I'm stuck, could you please help me to solve this problem ?
// The last result I am returning is a filtered array with all the nbs that are superior to 1 and then can't figure out how to get the result of matching pairs :-(
function countPairs(n, ar) {
const count = {};
ar.forEach((nb) => (count[nb] = (count[nb] || 0) + 1));
const values = Object.values(count);
const filter = values.filter((value) => value > 1);
return filter;
}
// 9 and 10 are the length of the arrays
console.log(countPairs(9, ar1))
console.log(countPairs(10, ar2))
Thank you very much for your help!
Perhaps there is a faster/better way to calculate this than this O(2n) solution, but it's something:
var ar1 = [10, 20, 20, 10, 10, 30, 50, 10, 20] // return 3 (2 pairs of 10 and 1 pair of 20)
var ar2 = [1, 1, 3, 1, 2, 1, 3, 3, 3, 3] // return 4 (2 pairs of 1 and 2 pairs of 3)
function countPairs(ar) {
var obj = {};
ar.forEach(item => {
obj[item] = obj[item] ? obj[item] + 1 : 1;
});
return Object.values(obj).reduce((acc, curr) => {
acc += Math.floor(curr / 2)
return acc;
}, 0);
}
console.log(countPairs(ar1))
console.log(countPairs(ar2))
This first calculates the number of occurences for each number and stores them in an Object. Once that is done, we reduce over the values and return the quotient from the division with 2 (to get the number of pairs in total).
Note: I removed the first argument from your function, because the array length is not needed as an argument. It can be obtained from the array you pass directly.
We can achieve this in O(n) time. Maintain an object which keeps track whether a number have been found before, if it was found before, then it makes up a pair, so we increment the pairs count. If not we make the entry of that number in the object 1
function countPairs(arr) {
let pairs = 0;
const obj = {};
arr.forEach(i => {
if (obj[i]) {
pairs += 1;
obj[i] = 0;
} else {
obj[i] = 1;
}
});
return pairs;
}
Simplest solution I can find:
create empty dictionary var t = {}; and use it to count each item in array arr.forEach (i => t[i] = (t[i] || 0) + 1);. After that take all keys Object.values(t) and sum .reduce((acc, p) => acc + ..., 0) each item counts divided by 2 p/2 with Int semantics of course Math.floor(...).
function countPairs(arr) {
var t = {};
arr.forEach (i => t[i] = (t[i] || 0) + 1);
return Object.values(t).reduce((acc, p) => acc + Math.floor(p/2), 0);
}
console.dir(countPairs([1,2,2,2,2,3]));
console.dir(countPairs([1,2,2,2,2,2,3]));
console.dir(countPairs([1,2,2,2,2,2,2,3]));
console.dir(countPairs([10, 20, 20, 10, 10, 30, 50, 10, 20]));
console.dir(countPairs([1, 1, 3, 1, 2, 1, 3, 3, 3, 3]));
First argument in your implementation is not necessary.
Please up-vote if answer was helpful
Concise approach with reduce method
const countPairs = arr => (pairs = [], arr.reduce((p, c) => (p[c] ? (pairs.push([p[c], c]), delete p[c]) : p[c] = c, p), {}), pairs.length)
console.log(countPairs([10, 20, 20, 10, 10, 30, 50, 10, 20]));
So, I wanted a more simpler solution to this problem since I'm just starting to learn to code and I'm teaching my self. I found this solution works perfectly for what you want. I didn't created this solution I found it on the internet(https://www.geeksforgeeks.org/count-equal-element-pairs-in-the-given-array/) I just translated it to JavaScript.
function countDuplicates(n, arr) {
var count = 0;
arr.sort();
for (var i = 0; i < n;) {
if (arr[i] === arr[i + 1]) {
count++;
i = i + 2;
} else {
i++;
}
}
return count;
}
console.log(countDuplicates(9, [10, 20, 20, 10, 10, 30, 50, 10, 20]));
There are some more concise answers here, but here's the solution I have for you:
function countDuplicates(arr) {
var counts = {}, sum = 0;
for (var i = 0; i < arr.length; i++) {
counts[arr[i].toString()] = (counts[arr[i].toString()] || 0) + 1;
}
for (var count in counts) {
if (Object.prototype.hasOwnProperty.call(counts, count)) sum += Math.floor(counts[count] / 2);
}
return sum;
}
console.log(countDuplicates([10, 20, 20, 10, 10, 30, 50, 10, 20]));
I hope I have helped
function numberOfPairs(array) {
let arr = [...array].sort();
let result = 0;
for (let i = 0; i < arr.length; i++) {
if (arr[i] == arr[i + 1]) {
result++;
arr.shift();
}
}
console.log(result);
}
numberOfPairs(['blue', 'blue', 'blue', 1, 2, 5, 2, 1]);
There are two arrays:
The first one contain numbers, and the second one contains "weight" of the first array values.
It works like this:
arr1 = [56,65,100,89,180,90];
"Weight" of the numbers are calculated in this way:
56 = 5+6 = 11;
65 = 6+5 = 11;
100 = 1+0+0 = 1; and so on..
So, arr2 = [11,11,1,17,9,9];
My question is how can I sort the values of the arr1 according to values of arr2?
I tried to modify simple bubble sort for this problem, but nothing changed.
function bubble(arr1, arr2) {
var len = arr1.length;
for (var i = 0; i < len; i++) {
for (var j = 0; j < len - i - 1; j++) {
if (arr2[j] > arr2[j + 1]) {
var temp = arr1[j];
arr1[j] = arr1[j + 1];
arr1[j + 1] = temp;
}
}
}
return arr1;
}
arr1 = [56, 65, 100, 89, 180, 90];
arr2 = [11, 11, 1, 17, 9, 9];
console.log(bubble(arr1, arr2));
I expect the output of the bubble function to be [100,180,90,56,65,89].
This is why:
FirstArray - [56,65,100,89,180,90] - arr1
"Weight of the values"[11,11, 1, 17, 9, 9 ] - arr2
Output [100,180,90,56,65,89]
[1, 9, 9 ,11,11,17]
You can just calculate the weight on the fly while sorting:
const arr = [56,65,100,89,180,90];
arr.sort( (a,b) =>
(a + '').split( '' ).reduce( (sum,x) => sum + +x, 0 ) -
(b + '').split( '' ).reduce( (sum,x) => sum + +x, 0 )
);
console.log( arr );
To achieve expected result, use below option of sorrting arr1 with logic mentioned in question
Sort arr1 bycomparing sum of digits
Convert number to string and split it to array
Use reduce sum all the digits and compare with the array elements
var arr1 = [56, 65, 100, 89, 180, 90];
var arr2 = [11, 11, 1, 17, 9, 9];
console.log(
arr1.sort(
(a, b) =>
a
.toString()
.split("")
.reduce((acc, v) => parseInt(acc) + parseInt(v)) -
b
.toString()
.split("")
.reduce((acc, v) => parseInt(acc) + parseInt(v))
)
);
codepen - https://codepen.io/nagasai/pen/WNeoaEv?editors=1010
I have an array like this one:
let array = [14, 42, 1, 3]
And I would like to get the arrays number mapped to this:
[1, 0, 3, 2]
Here is the reason:
1: because 14 is the second biggest number
0: because 42 is the biggest number
3: ...
What I have tried so far:
let sort = (array) => {
let result = []
let x = array.slice(0).sort((a, b) => b - a)
for (let elem of x) {
result.push(array.indexOf(elem))
}
console.log(result)
}
// Working
sort([14, 42, 1, 3]) // [1, 0, 3, 2]
// Not working, includes the index "0" two times
sort([14, 42, 14, 3]) // [1, 0, 0, 3]
// Expected: [1, 0, 2, 3]
You could take the indices and sort them by taking the value from the given array.
const sort = array => [...array.keys()].sort((a, b) => array[b] - array[a]);
console.log(sort([14, 42, 1, 3]));
console.log(sort([14, 42, 14, 3]));
It's because indexOf stops when it finds it's first result.
You could try to change the value to null once it's located the first time, or compare value to values already in the result and ignore those values.
let sort = (array) => {
let result = []
let x = array.slice(0).sort((a, b) => b - a)
for (let elem of x) {
result.push(array.indexOf(elem))
array[array.indexOf(elem)] = null;
}
console.log(result)
}
let sort = (arr) => {
let arr2 = arr.slice().sort((a, b) => b - a);
return arr.map((val) => {
return arr2.indexOf(val);
})
}
console.log(sort([14, 42, 1, 3]));
You can use a tracker object, map value and indexes as key/value pair and when looping though the array take the first index from respective key and shift it as well
let sort = (array) => {
let result = []
let x = array.slice(0).sort((a, b) => b - a)
let tracker = x.reduce((op,inp,i)=>{
op[inp] = op[inp] || []
op[inp].push(i)
return op
},{})
for (let elem of array) {
let val = tracker[elem][0]
tracker[elem].shift()
result.push(val)
}
console.log(result)
}
sort([14, 42, 1, 3]) // working
sort([14, 42, 14, 3]) // includes the index "0" two times
(() => {
function getBiggestOrder (nums) {
const lookup = {}
const result = nums.slice(0).sort((a, b) => b - a).map((num, i) => {
lookup[num] = i
return num
})
return nums.map(n => lookup[n])
}
const op = getBiggestOrder([14, 42, 1, 3])
console.log(op)
return op
})()
You are basically numbering the numbers from biggest to smallest. sort them in a duplicate array from biggest to smallest. And replace the original array numbers with their index in the duplicate array.
Original = [14, 42, 1, 3]
Duplicate = [42, 14, 3, 1]
Duplicate indexes are [0, 1, 2, 3]
so find 42 in the first array and replace it with the index of the 42 in the duplicate array, etc.