creating a new array from two arrays with a new attribute - javascript

I have two arrays. First array is an array of object with each object respresenting a vote for an item, the id represents the item that was voted.
The second array contains all the options for that poll.
I want to create a new array with each option from the poll options with a new attribute having the percentage of votes they got from the votes array.
This is the votes array.
votes = [{
vote_id: 1, person: {name: ‘alan’}
}, {
vote_id: 2, person: {name: ‘John’}
},{
vote_id: 1, person: {name: ‘khan’}
}, {
vote_id: 1, person: {name: ‘martin’}
},{
vote_id: 3, person: {name: ‘mike’}
}]
Options = [{
id: 1, title: ’sweet’}, {
id: 2: ’salty’}, {
id: 3, title: ’spicy’}, {
id: 4, title: ’bitter’}]
This is the new array that I want to create from the data available from the above two arrays
new array = [{
Id: 1, title: ’sugar’, percentage: 60%},
{Id: 2, title: ’salt’, percentage: 20% },
{id: 3, title: ’spice’, percentage: 20%},
{id: 4, title: ‘bitter’, percentage: 0%}]

Separate the problem into two parts:
get the counts,
map percentage.
const
votes = [{ vote_id: 1, person: { name: 'alan' } }, { vote_id: 2, person: { name: 'John' } }, { vote_id: 1, person: { name: 'khan' } }, { vote_id: 1, person: { name: 'martin' } }, { vote_id: 3, person: { name: 'mike' } }],
options = [{ id: 1, title: 'sweet' }, { id: 2, title: 'salty' }, { id: 3, title: 'spicy' }, { id: 4, title: 'bitter' }],
counts = votes.reduce((r, { vote_id }) => {
r[vote_id] = (r[vote_id] || 0) + 1;
return r;
}, {}),
result = options.map(o => ({ ...o, percentage: ((counts[o.id] || 0) * 100 / votes.length).toString() + ' %' }));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Related

How to enumare objects and total of them with the same key with another object in array js

I'm populing a pdf template with an array of employees, and now I need to count the number of employees working in a same department, I found a way to count the total of concurrences but I can't enumarate the employee working in the department and the total of them. Can you help me? Thanks!!!
For example, I have this array of objects
const employees = [
{
id: 1,
name: "john",
department: {
id: 1,
},
},
{
id: 1,
name: "Mike",
department: {
id: 3,
},
},
{
id: 1,
name: "Leona",
department: {
id: 1,
},
},
{
id: 1,
name: "Lara",
department: {
id: 1,
},
},
];
Result Expected:
const employees = [
{
id: 1,
name: "john",
department: {
id: 1,
},
totalForDeparments: "1/3",
},
{
id: 1,
name: "Mike",
department: {
id: 3,
},
totalForDeparments: "1/1",
},
{
id: 1,
name: "Leona",
department: {
id: 1,
},
totalForDeparments: "2/3",
},
{
id: 1,
name: "Lara",
department: {
id: 1,
},
totalForDeparments: "3/3",
},
];
First you group by the department.id - then you can iterate the original array adding the correct indexes.
const employees = [{id:1,name:"john",department:{id:1}},{id:1,name:"Mike",department:{id:3}},{id:1,name:"Leona",department:{id:1}},{id:1,name:"Lara",department:{id:1}},];
var grouped = employees.reduce(function(agg, item) {
agg[item.department.id] = agg[item.department.id] || {
count: 0,
current: 0
}
agg[item.department.id].count++;
return agg;
}, {});
employees.map(function(item) {
var data = grouped[item.department.id]
data.current++;
item.totalForDeparments = data.current + "/" + data.count
})
console.log(employees)
.as-console-wrapper {max-height: 100% !important}

Filter unknown deep nested array based on input value

First I must say sorry if this question is already answered, but I have not found the answer I am looking for :(
I have an array of objects with unknown nesting depth (it can be 20-30 or even more) and I want to filter it's 'name' property based on input field value.
public nestedArray = [
{id: 1, name: 'Example_1', children: []},
{id: 2, name: 'Test', children: []},
{id: 3, name: 'Test Name', children: [
{id: 10, name: 'Child name', children: [
{id: 20, name: 'Example_14', children: []},
{id: 30, name: 'Last Child', children: []}
]
}
]
}
];
The result I want to receive is an array of objects with only one level deep with 'name' field which includes input value.
For example my input value is 'am', so the result would be:
resultsArray = [
{id: 1, name: 'Example_1'},
{id: 3, name: 'Test Name'},
{id: 10, name: 'Child name'},
{id: 20, name: 'Example_14'}
];
There is no problem to do it on the first level like that:
public filter(array: any[], input_value: string): void {
array = array.filter(el => {
return el.name.toLowerCase().includes(input_value.toLowerCase()));
}
}
Thanks in advance!
You could map the array and their children and take a flat result of objects where the string is matching the name property.
const
find = value => ({ children, ...o }) => [
...(o.name.includes(value) ? [o] : []),
...children.flatMap(find(value))
],
data = [{ id: 1, name: 'Example_1', children: [] }, { id: 2, name: 'Test', children: [] }, { id: 3, name: 'Test Name', children: [{ id: 10, name: 'Child name', children: [{ id: 20, name: 'Example_14', children: [] }, { id: 30, name: 'Last Child', children: [] }] }] }],
result = data.flatMap(find('am'));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Another solution with a single result array and a classic approach.
const
find = (array, value) => {
const
iter = array => {
for (const { children, ...o } of array) {
if (o.name.includes(value)) result.push(o);
iter(children);
}
},
result = [];
iter(array);
return result;
},
data = [{ id: 1, name: 'Example_1', children: [] }, { id: 2, name: 'Test', children: [] }, { id: 3, name: 'Test Name', children: [{ id: 10, name: 'Child name', children: [{ id: 20, name: 'Example_14', children: [] }, { id: 30, name: 'Last Child', children: [] }] }] }],
result = find(data, 'am');
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

How to flatten the nested Array?

How do I flatten the nested Array in the Array?
Here is the example input Array,
const input = [
{
id: 1,
name: 'Charles',
otherFields: [{
id: 2,
name: 'Pung',
}, {
id: 3,
name: 'James',
}]
}, {
id: 4,
name: 'Charles',
otherFields: [{
id: 5,
name: 'Pung',
}, {
id: 6,
name: 'James',
}]
}
]
Output Array I want to get.
[{
id: 1,
name: 'Charles'
}, {
id: 2,
name: 'Pung',
}, {
id: 3,
name: 'James',
}, {
id: 4,
name: 'Charles'
}, {
id: 5,
name: 'Pung',
}, {
id: 6,
name: 'James',
}]
I want to somehow get the output in one statement like
input.map((sth) => ({...sth??, sth.field...})); // I'm not sure :(
With flatMap you can take out the otherFields property, and returning an array containing the parent item and the other array:
const input = [{
id: 1,
name: 'Charles',
otherFields: [{
id: 2,
name: 'Pung',
}, {
id: 3,
name: 'James',
}]
}];
console.log(
input.flatMap(({ otherFields, ...item }) => [item, ...otherFields])
);
For more than one level, you could take a recursive approach of flattening.
const
flat = ({ otherFields = [], ...o }) => [o, ...otherFields.flatMap(flat)],
input = [{ id: 1, name: 'Charles', otherFields: [{ id: 2, name: 'Pung' }, { id: 3, name: 'James', otherFields: [{ id: 4, name: 'Jane' }] }] }],
result = input.flatMap(flat);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Counting number of occurances of in primary array A that are in array B

I want to get the count of Items in array A that are in B and return an array C that contains the count elements.
array A is:
arrA = [{id:1,name:"Nairobi"},{id:2,name:"New Delhi"},{id:3,name:"Singapore"},{id:4,name:"London"}]
array B is:
arrB = [{id:1,id_fk:1,name:"Steve"},{id:2,id_fk:1,name:"John"},{id:3,id_fk:2,name:"Stella"},{id:4,id_fk:3,name:"Kemi"},{id:5,id_fk:3,name:"Kelly"},{id:6,id_fk:4,name:"James"},{id:7,id_fk:4,name:"Marley"},{id:8,id_fk:4,name:"Oliver"}]
Using id_fk in array B as a "foreign key" for id in array A, the expected output is
[2,1,2,3]
My implementation code is
for (let arrayA of arrA){
let count = arrB.filter(a =>
{return a.id_fk === arrayA.id}).length;
}
You could take a Map and get the id as keys in the wanted order and reduce the second array for counting items with id_fk. As result take an array of the values of the map.
This approach uses a single loop for getting the id as keys and another loop for counting.
var arrA = [{ id: 1, name: "Nairobi" }, { id: 2, name: "New Delhi" }, { id: 3, name: "Singapore" }, { id: 4, name: "London" }],
arrB = [{ id: 1, id_fk: 1, name: "Steve" }, { id: 2, id_fk: 1, name: "John" }, { id: 3, id_fk: 2, name: "Stella" }, { id: 4, id_fk: 3, name: "Kemi" }, { id: 5, id_fk: 3, name: "Kelly" }, { id: 6, id_fk: 4, name: "James" }, { id: 7, id_fk: 4, name: "Marley" }, { id: 8, id_fk: 4, name: "Oliver" }],
result = Array.from(arrB
.reduce(
(m, { id_fk }) => m.set(id_fk, m.get(id_fk) + 1),
new Map(arrA.map(({ id }) => [id, 0]))
)
.values()
);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
A result with a hash table and new objects with a count property.
var arrA = [{ id: 1, name: "Nairobi" }, { id: 2, name: "New Delhi" }, { id: 3, name: "Singapore" }, { id: 4, name: "London" }],
arrB = [{ id: 1, id_fk: 1, name: "Steve" }, { id: 2, id_fk: 1, name: "John" }, { id: 3, id_fk: 2, name: "Stella" }, { id: 4, id_fk: 3, name: "Kemi" }, { id: 5, id_fk: 3, name: "Kelly" }, { id: 6, id_fk: 4, name: "James" }, { id: 7, id_fk: 4, name: "Marley" }, { id: 8, id_fk: 4, name: "Oliver" }],
hash = {},
result = arrA.map(o => Object.assign(hash[o.id] = {}, o, { count: 0 }));
arrB.forEach(({ id_fk }) => hash[id_fk].count++);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
I would do it like this. https://jsfiddle.net/6egs7uLy/
let counts = [];
arrA.forEach((item, index) => {
let count = 0;
arrB.forEach((item2, index) => {
if(item['id'] === item2['id_fk']) {
count++;
}
})
counts.push(count);
count = 0;
})

Merge Duplicate object in array

I have an array I need to merge duplicate values with the sum of amount.
What would be an efficient algorithm
var arr = [{
item: {
id: 1,
name: "Abc"
},
amount: 1
}, {
item: {
id: 1,
name: "Abc"
},
amount: 2
}, {
item: {
id: 2,
name: "Abc"
},
amount: 2
},{
item: {
id: 1,
name: "Abc"
},
amount: 2
}]
I need solution as
[{
item: {
id: 1,
name: "Abc"
},
amount: 5
}, {
item: {
id: 2,
name: "Abc"
},
] amount: 2
}]
simply use Object.values() with Array.reudce() to merge objects and then get the values:
var arr = [{ item: { id: 1, name: "Abc" }, amount: 1 }, { item: { id: 1, name: "Abc" }, amount: 2 }, { item: { id: 2, name: "Abc" }, amount: 2 },{ item: { id: 1, name: "Abc" }, amount: 2 }];
var result = Object.values(arr.reduce((a,curr)=>{
if(!a[curr.item.id])
a[curr.item.id] = Object.assign({},curr); // Object.assign() is used so that the original element(object) is not mutated.
else
a[curr.item.id].amount += curr.amount;
return a;
},{}));
console.log(result);
used map to catch em all :D
var arr = [{ item: { id: 1, name: "Abc" }, amount: 1 }, { item: { id: 1, name: "Abc" }, amount: 2 }, { item: { id: 2, name: "Abc" }, amount: 2 },{ item: { id: 1, name: "Abc" }, amount: 2 }];
var res = {};
arr.map((e) => {
if(!res[e.item.id]) res[e.item.id] = Object.assign({},e); // clone, credits to: #amrender singh
else res[e.item.id].amount += e.amount;
});
console.log(Object.values(res));

Categories

Resources