Count all values in object where X is the first key letter - javascript

I would like to count all values where a letter appears first and return the letter with atleast half of all values in my object so for example I assuming I have an object like this
const sample = { "A,B,C": 4, "B,C,A": 3, "C,B,A": 2, "A,C,B": 2 };
I would return A because if you count all the values where A appears first you would get 6 (4+2)
This is what I currently have:
for (let votes of Object.values(sample)) {
sum += votes
}
stretchWin = Math.round(sum / 2)
winner = Object.entries(sample)
.filter(([, val]) => val >= stretchWin)
.map(([keys]) => keys)
With this I am getting an empty array because I am not counting all the values assigned to A

Iterate over the whole sample first to get a sum of the values by the first letter first, then iterate over that new object to identify which values match the target of half the total.
const sample = {
"A,B,C": 4,
"B,C,A": 3,
"C,B,A": 2,
"A,C,B": 2
};
const sumByChar = {};
for (const [key, value] of Object.entries(sample)) {
const char = key[0];
sumByChar[char] = (sumByChar[char] ?? 0) + value;
}
let sum = 0;
for (let votes of Object.values(sample)) {
sum += votes
}
const targetSum = Math.round(sum / 2);
const winners = Object.entries(sumByChar)
.filter(([, val]) => val >= targetSum)
.map(([key]) => key);
console.log(winners);

I'm not completely sure what you mean what the outcome should be. If I understand correctly you want something like this??
const sample = { "A,B,C": 4, "B,C,A": 3, "C,B,A": 2, "A,C,B": 2 };
const totalSum = Object.values(sample).reduce(
(previousValue, currentValue) => previousValue + currentValue,
0
);
const stretchWin = Math.round(totalSum / 2);
const winner = Object.entries(sample)
.filter(([key, value]) => {
const isFirstLetterA = key.startsWith("A");
return isFirstLetterA || value >= stretchWin;
})
.map(([key, value]) => value)
.reduce((previousValue, currentValue) => previousValue + currentValue, 0);
console.log(winner);

Related

JavaScript sum array using recursion

My task is to sum elements of an array and add it to second parameter (number) using recursion.
Return only gives me last value of sum. I would appreciate any feedback :)
const getArraySum = (numbersArray, initialValue) => {
// let sum = initialValue
// for (let i = 0; i < numbersArray.length; i++) {
// sum += numbersArray[i]
// } return sum
if (numbersArray.length === 0 ) {
return initialValue
} else {
let sum = 0
sum += numbersArray[numbersArray.length-1]
console.log (numbersArray)
numbersArray.pop()
console.log (sum)
getArraySum (numbersArray)
return sum + initialValue
}
};
const result1 = getArraySum([4,7,10], 5)
console.log (result1)
You're ignoring the return value of the recursive call to getArraySum. Instead, you should add it to the returned value:
const getArraySum = (numbersArray, initialValue) => {
if (numbersArray.length === 0) {
return initialValue
}
return numbersArray.pop() + getArraySum(numbersArray, initialValue);
};
const result = getArraySum([4,7,10], 5)
console.log (result)
Note that the initialValue should only be taken into consideration once, in the end condition where the array is empty.
The idea is to split an array into head (=the first element or null for an empty array) and tail (everything else). Then, establish that the sum is head + sum(tail):
let sum = ([head = null, ...tail]) =>
head === null ? 0 : head + sum(tail)
console.log(sum([1,2,3,4]))
Having an initial value is a silly requirement, but it goes the same way:
let sum = ([head = null, ...tail], init = 0) =>
init + (head === null ? 0 : head + sum(tail))
console.log(sum([1, 2, 3, 4], 100))
You could take the single values a summing variable and return immediately if the array is empty.
Otherwise return the function call with a new shorter array and hte sum of sum and the first element.
const
getSum = (numbers, sum = 0) => {
if (!numbers.length) return sum;
return getSum(numbers.slice(1), sum + numbers[0]);
};
console.log (getSum([4, 7, 10], 5));
As long as the array has an element, return last element (pop) plus getArraySum([rest of the array]), otherwise return initial value:
const getArraySum = (numbersArray, initialValue) => {
if (numbersArray.length === 0 ) {
return initialValue
} else {
return numbersArray.pop() + getArraySum(numbersArray, initialValue);
}
};
const result1 = getArraySum([4,7,10], 5)
console.log (result1)

sample array n^2 times without the same number occurring twice in a row and not repeating every n

I'm trying to write a function that has the arguments of the array to sample arr and the number of samples, size (which is sqaured) and randomly samples from the original array:
arr = [1,2,3,4]
single_number = (x) => {
return x[Math.floor(Math.random()*x.length)];
}
randomize = (arr, size) => {
return Array(size*size).fill().map(x => single_number(arr))
}
randomize(arr, 5)
I want to add the additional requirements to my randomize function:
no number shows up twice in a row
make sure every sizeth item is not the same as the one before it
For example
randomize([1,2,3,4], 2)
[2,4,3,2,4,1,1,2,2,1,4,1,1,1,3,1,1,4,4,1,3,3,2,2,3]
CASE (1)
[
2,4,3,2,4,
2,1,
2,2, // illegal!
1,4,
1,1,1, // illegal!
3,
1,1, // illegal!
4,4, // illegal!
1,
3,3, // illegal!
2,2, // illegal!
3
]
CASE (2)
[
2,4,3,2,4, [0] === 2
2,1,2,2,1, [5] === 2 // illegal!
4,1,1,1,3,
1,1,4,4,1,
3,3,2,2,3
]
I'm trying to use functional programming and avoid a for loop if possible since I think I can do this with a nested for loop?
Well, this isn't as pretty as one would hope, but I think it accomplishes the objective: Iterate size^2 times and choose random elements from the input, taking care to exclude the last value and last nth value chosen...
const randomize = (array, size) => {
const rand = () => Math.floor(Math.random() * array.length);
const randExcept = exclude => {
let v = array[rand()];
while (exclude.includes(v)) v = array[rand()];
return v;
}
const indexes = Array.from(Array(size*size).keys());
let lastV = null, nthV = null;
return indexes.map(i => {
let exclude = nthV!==null && i%size===1 ? [lastV, nthV] : [lastV];
let v = randExcept(exclude);
lastV = v;
if (i%size===1) nthV = v;
return v;
})
}
console.log( JSON.stringify(randomize([1,2,3,4], 2)) )
This defines nth values by the count into the array, so for size===2, the constraint is that every second element (indexes 1,3,5...) can't be equal to the prior second element.
I'd probably do something like this:
const values = [1,2,3,4]
function randomize(values, size) {
let prev;
let prevNth;
return Array(size*size).fill().map( randomNumber );
function randomNumber(_,i) {
let value, ok;
do {
value = values[ Math.floor( Math.random() * values.length ) ];
ok = value != prev;
if ( i % size === 0) {
ok = ok && value != prevNth;
prevNth = value;
}
prev = value;
} while (!ok);
return value;
}
}
arr = randomize(values, 5)
console.log(JSON.stringify(arr));
Or this, using a generator to generate the appropriately sized stream of randomness:
const values = [1,2,3,4];
const arr1 = Array.from( randomValues(5,values) );
console.log(JSON.stringify(arr1));
function *randomValues(n, values) {
const limit = n*n;
let prev, prevNth;
for ( let i = 0 ; i < limit ; ++i ) {
const isNthValue = i % n === 0;
const value = randomValue( values, prev, isNthValue ? prevNth : undefined );
yield value;
prev = value;
prevNth = isNthValue ? value : prevNth;
}
}
function randomValue(values, test1, test2 ) {
let value;
do {
value = values[ Math.floor( Math.random() * values.length ) ];
} while (value === test1 || value === test2 );
return value;
}

Count the repetition of an element in an array using a function with one parameter

Good Day, I am trying to count how many times a particular element in an array appears. I tried but my code below counts only one of the array even if it appears more than once (this is not the problem). I want it to return the amount of time each element appears. For example
let arr = [1, 3, 2, 1];
this should return
{1:2} {3:1} {2:1}
My code returns 3 (as in it just doesn't count one twice)
How do i go about this?
Below is my code
function numberCount(number) {
let count = 0;
number.forEach(function (item, index) {
if (number.indexOf(item) == index) count++;
});
console.log(count);
}
While iterating over number (better to call it arr, it's an array, not a number), use an object to keep track of the number of times each number has occured so far. Then, iterate over the resulting object's entries to create the objects desired:
let arr = [1, 3, 2, 1];
function numberCount(arr) {
let count = 0;
const obj = arr.reduce((a, num) => {
a[num] = (a[num] || 0) + 1;
return a;
}, {});
return Object.entries(obj).map(([key, val]) => ({ [key]: val }));
}
console.log(numberCount(arr));
Numeric keys always come in numeric order in an object. If you want the objects in the output to come in insertion order (eg, the object with key 3 before the object with key 2), then use a Map instead of an object (map keys will be iterated over in insertion order):
let arr = [1, 3, 2, 1];
function numberCount(arr) {
let count = 0;
const map = arr.reduce((a, num) => (
a.set(num, (a.get(num) || 0) + 1)
), new Map());
return [...map.entries()]
.map(([key, val]) => ({ [key]: val }));
}
console.log(numberCount(arr));
You should filter out these numbers, then use the length:
let arr = [1, 3, 2, 1];
function itemCount(array) {
var sorted = array.sort()
var uniqueCount = sorted.filter((v, i, a) => a.indexOf(v) == i);
var count = [];
uniqueCount.forEach(item => {
var itemCount = sorted.filter(e => e == item).length;
count.push({[item]: itemCount});
});
return count;
}
console.log(itemCount(arr));
I would suggest not reinventing the wheel, and instead use lodash which already has this function. Using countBy() you will get an object you can then convert into your desired result. For example:
const arr = [1, 3, 2, 1]
const count = _.countBy(arr)
const result = Object.keys(count).map(k => ({ [k]: count[k] }))
console.log(result)
<script src="https://cdn.jsdelivr.net/npm/lodash#4.17.11/lodash.min.js"></script>

calculate the percent instead the sum

Actually my function calculate the sum of all same keys in each object
const arr = [{id:1, "my color":1,"my fruit":4},{id:2,"my color":2,"my fruit":4}];
const res = arr.reduce((a, { id, ...rest }) => {
Object.entries(rest).forEach(([key, val]) => {
a[key] = (a[key] || 0) + val;
});
return a;
}, {});
result is >> [{"my color":3,"my fruit":8}
I'd like to get their percent (value/sum of values) and not instead their sum, like this
{ "my color": 27, "my fruit": 73 }
Try following
var obj = {"my color":3,"my fruit":8};
var total = Object.values(obj).reduce((a,c) => a+c, 0);
Object.keys(obj).forEach(k => obj[k] = Math.round(obj[k]*100/total));
console.log(obj);
Well just sum up all values first, then divide each entry by that:
// Sum up all properties with same key
const sum = { };
for(const entry of array) {
for(const [key, value] of Object.entries(entry)) {
sum[key] = (sum[key] || 0) + value;
}
}
// Map the array to an array of percentages
const percentage = array.map(entry => {
const result = {};
for(const [key, value] of Object.entries(entry)) {
result[key] = value / sum[key] * 100;
}
return result;
});

Finding a Single Integer in an array using Javascript

I was able to pull all single integers after 'reduce', but not working when there's all duplicates and output should be 0, not hitting my else or else if - code keeps outputting 0 vs the single integers
var singleNumber = function(nums) {
var sorted_array = nums.sort();
for (var i=0; i < sorted_array.length; i++){
var previous = sorted_array[i-1];
var next = sorted_array[i+1];
var singles = {key: 0};
var singlesArray = [];
if (sorted_array[i] !== previous && sorted_array[i] !== next){
singlesArray.push(sorted_array[i]);
singlesArray.reduce(function(singles, key){
singles.key = key;
//console.log('key', key);
return singles.key;
},{});
}
else if(singlesArray.length === 0) {
singles.key = 0;
return singles.key;
}
}
console.log('singles.key', singles.key);
return singles.key;
};
console.log(singleNumber([2,1,3,4,4]));
// tests
const n1 = [1,2,3,4,4] //[1,2,3]
const n2 = [1] //[1]
const n3 = [1,1] //0
const n4 = [1,1,1] //0
const n5 = [1,5,3,4,5] //[1,3,4]
const n6 = [1,2,3,4,5] //[1,2,3,4,5]
const n7 = [1,5,3,4,5,6,7,5] //[1,3,4,6,7]
const singleNumber = numbers => {
const reducer = (acc, val) => {
// check to see if we have this key
if (acc[val]) {
// yes, so we increment its value by one
acc[val] = acc[val] + 1
} else {
// no, so it's a new key and we assign 1 as default value
acc[val] = 1
}
// return the accumulator
return acc
}
// run the reducer to group the array into objects to track the count of array elements
const grouped = numbers.reduce(reducer, {})
const set = Object.keys(grouped)
// return only those keys where the value is 1, if it's not 1, we know its a duplicate
.filter(key => {
if (grouped[key] == 1) {
return true
}
})
// object.keys makes our keys strings, so we need run parseInt to convert the string back to integer
.map(key => parseInt(key))
// check to array length. If greater than zero, return the set. If it is zero, then all the values were duplicates
if (set.length == 0) {
return 0
} else {
// we return the set
return set
}
}
console.log(singleNumber(n7))
https://jsbin.com/sajibij/edit?js,console

Categories