I have two arrays of numbers a and b, I want to find closest pair of numbers from this array. But I am stuck inside the reducer, with given match to.
Expected output is
[
{
"dif": 1,
"val": 3,
"to": 4
},
{
"dif": 2,
"val": 3,
"to": 5
},
{
"dif": 2,
"val": 8,
"to": 6
}
]
const a = [1,2,3,8]
, b = [4,5,6]
const result = b.map(to => {
return a
.map(v => {return {val:v}})
.reduce((prev, curr) => {
return Math.abs(curr.val - to) < Math.abs(prev.val - to) ? {dif:Math.abs(prev.val - to), val:curr.val, to} : {dif: Math.abs(prev.val - to), val:prev.val, to}
});
})
console.log(result)
There is one correction in your code. {dif:Math.abs(prev - to), val:curr.val, to} should be {dif:Math.abs(curr.val - to), val:curr.val, to}
const a = [1,2,3,8]
, b = [4,5,6]
const result = b.map(to => {
return a
.map(v => {return {val:v}})
.reduce((prev, curr) => {
return Math.abs(curr.val - to) < Math.abs(prev.val - to) ? {dif:Math.abs(curr.val - to), val:curr.val, to} : {dif: Math.abs(prev.val - to), val:prev.val, to}
});
})
console.log(result)
another choice:
const a = [1, 2, 3, 8],
b = [4, 5, 6];
const result = b.map(v => {
return a.reduce((re, value) => {
let updateRule = re.val === undefined || (re.val !== undefined && Math.abs(value - re.to)) < re.dif;
return updateRule ? { val: value, dif: Math.abs(value - re.to), to: v } : re;
}, { to: v });
});
console.log(result);
You could generate the cartesian product and sort by difference.
var a = [1, 2, 3, 8],
b = [4, 5, 6],
result = a
.reduce((r, c) => r.concat(b.map(d => ({ dif: Math.abs(c - d), val: c, to: d }))), [])
.sort((a, b) => a.dif - b.dif);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Related
I have an object as below:
var countryobj = {
"Canada": 10,
"Peru": 1,
"Argentina": 5,
"Colombia": 2,
"Mexico": 8
};
I want to get the first 3 smallest key value pair so that my output would be:
Peru: 1
Colombia: 2
Argentina: 5
Just get the Object.entries and sort them based on their value in ascending order, then print the first three items formatted how you like.
var countryobj = {
"Canada": 10,
"Peru": 1,
"Argentina": 5,
"Colombia": 2,
"Mexico": 8
};
const entries = Object.entries(countryobj).sort(([, a], [, b]) => a - b);
for (let i = 0; i < 3; i++) {
console.log(entries[i][0] + ": " + entries[i][1]);
}
function getRange(obj, count) {
return Object.entries(obj)
.sort(([, prev], [, next]) => a - b)
.slice(0, count)
.reduce(
(result, [key]) => ({
...result,
[key]: obj[key],
}),
{},
);
}
If I have an array of numbers and I want to get the one that occurs the most frequent, yet there are two possible answers, Im having trouble sorting that part out. For example, below should return 1 and 7 but I only get 7. Any help is appreciated.
let arr = [1, 1, 2, 3, 4, 5, 6, 7, 7];
function findMode(numbers) {
let counted = numbers.reduce((acc, curr) => {
if (curr in acc) {
acc[curr]++;
} else {
acc[curr] = 1;
}
return acc;
}, {});
let mode = Object.keys(counted).reduce((a, b) => counted[a] > counted[b] ? a : b);
return mode;
}
console.log(findMode(arr));
You could group equal items in sub-arrays, then sort by sub-array length and retrieve the first values with the same array length like this:
const arr = [1, 1, 2, 3, 4, 5, 6, 7, 7],
output = arr
.sort((a, b) => a - b)
.reduce(
(acc, cur, i, { [i - 1]: last }) =>
(cur === last ? acc[acc.length - 1].push(cur) : acc.push([cur])) && acc,
[]
)
.sort((a, b) => b.length - a.length)
.reduce(
(a, b, _, { 0: first }) => (first.length === b.length ? [...a, b[0]] : a),
[]
);
console.log(output);
You can use an array as the accumulator.
let arr = [1, 1, 2, 3, 4, 5, 6, 7, 7];
function findMode(numbers) {
let counted = numbers.reduce((acc, curr) => {
if (curr in acc) {
acc[curr]++;
} else {
acc[curr] = 1;
}
return acc;
}, {});
let mode = Object.keys(counted).reduce((acc, curr) => {
if(!acc.length || counted[curr] > counted[acc[0]]) return [curr];
if(counted[curr] === counted[acc[0]]) acc.push(curr);
return acc;
}, []);
return mode;
}
console.log(findMode(arr));
Alternatively, you can find the highest frequency and then use filter to find numbers with that frequency.
let arr = [1, 1, 2, 3, 4, 5, 6, 7, 7];
function findMode(numbers) {
let counted = numbers.reduce((acc, curr) => {
if (curr in acc) {
acc[curr]++;
} else {
acc[curr] = 1;
}
return acc;
}, {});
let mode = Math.max(...Object.values(counted));
return Object.keys(counted).filter(x => counted[x] === mode);
}
console.log(findMode(arr));
You can keep track of the max number of occurrences in the first loop, and then use Array#filter to get the keys with such value:
function findMode(numbers) {
let max = 0;
const counted = numbers.reduce((acc, curr) => {
if (curr in acc) acc[curr]++;
else acc[curr] = 1;
if(acc[curr] > max) max = acc[curr];
return acc;
}, {});
const mode = Object.keys(counted)
.filter(key => counted[key] === max)
.map(Number);
return mode;
}
console.log( findMode([1, 1, 2, 3, 4, 5, 6, 7, 7]) );
As the whole action is happening within a function scope we can also do it with two .forEach() loops: in the first one we collect the counts and in the second one we then assemble a results array with the "winners".
By using a map for collecting the counts we avoid the type conversion to string that would have occurred had we used a plain object.
let arr = [1, 1, 2, "1", 3, 4, "1", 5, 6, 7, 7];
function findMode(nums) {
let cn=new Map(),mx=0,res;
nums.forEach(n=>cn.set(n,(cn.get(n)||0)+1));
[...cn.entries()].forEach(([v,c])=>{
if(c>mx) {res=[v];mx=c}
else if (c===mx) res.push(v) });
return res;
}
console.log(findMode(arr));
Given the array const vals = [1, 2, 3, 4, 5, 6, 7, 8, 9];
How can I filter and return a new array of indexed key/value pair objects for example:
const vals = [1, 2, 3, 4, 5, 6, 7, 8, 9];
// My fail attempt using filter()
let obj = vals.filter((n, i) => {
return new Object({ i: n % 2 });
});
return obj;
// expected result [{1:2}, {3:4}, {5:6}, {7:8}]
I need to keep the index values as I will filter 2 different arrays with different criteria and associated them later.
Update
Second attempt using map() as suggested in the comments
let obj = vals.map((n, i) => {
if (n % 2) {
return { [i]: n };
}
});
Gives me the following:
[{0:1}, undefined, {2:3}, undefined, {4:5}, undefined, {6:7}, undefined, {8:9}]
To get a list of { key: value } objects where key is the index, and the values are only even without the odd values, you can do this:
const vals = [1, 2, 3, 4, 5, 6, 7, 8, 9];
const result = vals.map((v, i) => [i, v])
.filter(([_, v]) => v % 2 == 0)
.map(([i, v]) => ({ [i]: v }));
console.log(result);
With the first map, you make a list of [[0, 1], ...] pairs to save the index for later.
Then you filter your index-value pairs so only even values remain.
Then you pack those pairs into an object in another map.
This can be done more efficiently with a single iteration using reduce:
const vals = [1, 2, 3, 4, 5, 6, 7, 8, 9];
const result = vals.reduce((a, v, i) => {
if (v % 2 == 0) {
a.push({ [i]: v });
}
return a;
}, []);
console.log(result);
Youn can try simple for loop or the reduce function
let arr = [];
for(let i = 0; i<vals.length-1;i += 2)
{
let obj={};
obj[vals[i]]=vals[i+1];
arr.push(obj);
};
For example we have an array
const nums = [1,1,8,12,2,3,3,3,7];
If I want to map number of occurrences of each array member I could use something like
function extractDupes(arr) {
return arr.reduce(function (acc, item) {
if (item in acc) {
acc[item]++
}
else {
acc[item] = 1
}
return acc
}, {})
}
This would return object like
{ '1': 2, '2': 1, '3': 3, '7': 1, '8': 1, '12': 1 }
Is there an optimal way to filter out numbers which are showing up more than once just with using reduce (in a single pass) and have just
{ '1': 2, '3': 3 }
const nums = [1,1,8,12,2,3,3,3,7];
const dups = {};
nums.forEach((v, i, s) => {
if (s.indexOf(v) != i)
if (dups[v])
dups[v]++;
else
dups[v] = 2;
});
console.log(dups);
If you also want the array of unique values at the end:
const nums = [1,1,8,12,2,3,3,3,7];
const dups = {};
const uniques = nums.filter((v, i, s) => {
if (s.indexOf(v) != i)
if (dups[v])
dups[v]++;
else
dups[v] = 2;
else
return true;
});
console.log(dups);
console.log(uniques);
have a staging variable for values equaling 1 and promote them to the main result when they're hit the second time?
const nums = [1,1,8,12,2,3,3,3,7];
function extractDupes(arr) {
const staging = {}
return arr.reduce(function (acc, item) {
if (item in acc) {
acc[item]++
} else if(item in staging) {
acc[item] = 2
delete staging[item]
} else {
staging[item] = 1
}
return acc
}, {})
}
document.getElementById('hi').innerHTML = JSON.stringify(extractDupes(nums))
<div id="hi"></div>
You could take a nested property for the final object.
function extractDupes(array) {
return array
.reduce(function(acc, item) {
if (acc[item]) acc.dupes[item] = (acc.dupes[item] || 1) + 1;
else acc[item] = true;
return acc;
}, { dupes: {} })
.dupes;
}
const nums = [1, 1, 8, 12, 2, 3, 3, 3, 7];
console.log(extractDupes(nums))
You could use Object.entries to transform the object to key-value pairs then filter the pair that have value greater than 1, and then transform the pairs back to object by Object.fromEntries
const nums = [1, 1, 8, 12, 2, 3, 3, 3, 7]
function extractDupes(arr) {
return Object.fromEntries(
Object.entries(
arr.reduce(function (acc, item) {
if (item in acc) {
acc[item]++
} else {
acc[item] = 1
}
return acc
}, {})
).filter(([key, value]) => value > 1)
)
}
console.log(extractDupes(nums))
let arrAssist = [];
array.sort();
arrAssist.push(inventory[0]);
for(var i = 1; i < array.length; i++){
if(array[i] != array[i - 1]){
arrAssist.push(array[i]);
}
}
in this example, arrAssist contains the array with no duplicates
It has been answered and accepted but anyhow here is how i would do.
const nums = [1, 1, 8, 12, 2, 3, 3, 3, 7];
const map = nums.reduce((acc, num) => {
acc.frequency[num] = (acc.frequency[num] || 0) + 1;
if (acc.frequency[num] > 1) {
acc.replicates[num] = acc.frequency[num];
}
return acc;
}, { frequency: {}, replicates: {} });
console.log(map);
Can I make one histogram in javascript with one Array, for example:
array = [1, 2, 2];
result:
1: *
2: **
I tried this:
array.reduce((acum,cur) => Object.assign(acum,{[cur]: (acum[cur] | 0)+1}),{});
my result:
{1: 1, 2: 2}
Thank you
You need a logical OR || (and not a bitwise OR |).
var array = [1, 2, 2],
result = array.reduce((acum, cur) => ({ ...acum, [cur]: (acum[cur] || 0) + 1 }), {});
console.log(result);
If you like to take '*' instead of the count, you could add stars.
var array = [1, 2, 2],
result = array.reduce((acum, cur) => ({ ...acum, [cur]: (acum[cur] || '') + '*' }), {});
console.log(result);