How Can I Use Ternary Conditional Operator Without Else? - javascript

I got a code block like this
const numbers = [1, 2, 3, 4, 5, 6];
const newNumbers = numbers.reduce((acc, num) => {
acc.push(num > 3 ? num : null);
return acc;
}, []);
console.log('new Numbers', newNumbers);
//returns new Numbers,[null, null, null, 4, 5, 6]
But I don't want null values to be pushed in array. I want to perform the action like this but without if:
const newNumbers = numbers.reduce((acc, num) => {
if (num > 3) {
acc.push(num);
}
return acc;
}, []);
console.log(newNumbers);
//returns new Numbers,[4, 5, 6]

How Can I Use Ternary Conditional Operator Without Else?
No. The conditional operator always has to "return" a value. Imagine it was possible to leave out the alternative (e.g. arr.push(num > 3 ? num)), what value would be pushed to the array?
In this specific case there is a better tool for the job: Array#filter:
const newNumbers = numbers.filter(num => num > 3)

Use && instead of ?,
const numbers = [1, 2, 3, 4, 5, 6];
const newNumbers = numbers.reduce((acc, num) => {
num > 3 && acc.push(num)
return acc;
}, []);
console.log(newNumbers);
//returns new Numbers,[4, 5, 6]

You can always do:
num > 3 ? acc.push(num) : {}

Related

Javascript - Find most frequent number in array, even if there are two

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));

How to filter an array and return new array of objects with indexed values?

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);
};

immer - Nested produce calls are not working as expected

const { produce } = require("immer");
const outer = produce((draft) => {
return inner(draft);
}, {});
const inner = produce((draft) => {
draft.arr = [4, 5, 6];
}, {});
outer().arr.sort();
inner().arr.sort();
link: https://codesandbox.io/s/boring-wiles-ezqtr
There is an error on inner().arr.sort(). (read-only error)
My expectation is that outer().arr.sort() also be an error.
Is there something I'm doing wrong here?
Not sure why you want an nested produce but as my understanding you are trying to write a function that leverage immer to sort an array so, to avoid changing initial array.
This is how you could go and from here use another "produce" function that does that. (Code Sandbox)
const { produce } = require("immer")
const baseArray = [6, 10, 3, 2, 1]
const baseArray2 = [17, 9, 10, 3, 2, 1];
function sortedF(state) {
return produce(state, (draft) => {
const sorted = draft.sort((a, b) => a - b)
console.log(sorted);
});
}
const sorted1 = sortedF(baseArray)
console.log(sorted1); // [1, 2, 3, 6, 10]
This use a carried solution curried-produce
const sortedCarried = produce((draft) => {
const sorted2 = draft.sort((a, b) => a - b)
});
const sorted2 = sortedCarried(baseArray2)
console.log(sorted2); // [1, 2, 3, 9, 10, 17]

How I can Histogram in Javascript with Array

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);

how to sort an array of numbers in javascript making sure that the first count finished before adding duplicates?

I have this array of numbers that i am working with that currently look this;
count = [1,4,3,1,2,3,4,5,6,2,3,5,7];
How can i transform and sort it to make it look like this;
count = [1,2,3,4,5,6,7,1,2,3,3,4,5];
Please help, any idea out there on how to approach this?
1) Get unique elements and sort
2) Get remaining elements and sort
3) combine (1) and (2) arrays.
count = [1, 4, 3, 1, 2, 3, 4, 5, 6, 2, 3, 5, 7];
const spSort = arr => {
const uniq = [...new Set([...arr])];
const rem = [];
const temp_set = new Set([...arr]);
arr.forEach(x => {
if (temp_set.has(x)) {
temp_set.delete(x);
} else {
rem.push(x);
}
});
return [...uniq.sort(), ...rem.sort()];
};
console.log(spSort(count));
Use a Set to create unique numbers and a hash object to keep count of duplicates:
const count = [1, 4, 3, 1, 2, 3, 4, 5, 6, 2, 3, 5, 7];
const hash = count.reduce((obj, num) => {
obj[num] = obj[num] ? ++obj[num] : 1;
return obj;
}, {});
const uniq = [...new Set(count)].sort();
uniq.forEach((num, _, arr) => {
while (--hash[num]) arr.push(num);
});
console.info(uniq);

Categories