const portfolio = [
{ name: 'Mark', stock: 'FB' },
{ name: 'Steve', stock: 'AAPL' },
{ name: 'Tim', stock: 'AAPL' },
{ name: 'Steve', stock: 'MSFT' },
{ name: 'Bill', stock: 'MSFT' },
{ name: 'Bill', stock: 'AAPL' },
];
// Output
const shareholder = [
{ stock: 'AAPL', name: ['Steve', 'Bill', 'Tim'], count: 3 },
{ stock: 'MSFT', name: ['Steve', 'Bill'], count: 2 },
{ stock: 'FB', name: ['Mark'], count: 1 },
];
if I create one function which take input array as param and this will return output array in jS
CodePudding user response:
One way using reduce
and Object.values
const portfolio = [{
name: 'Mark',
stock: 'FB'
},
{
name: 'Steve',
stock: 'AAPL'
},
{
name: 'Tim',
stock: 'AAPL'
},
{
name: 'Steve',
stock: 'MSFT'
},
{
name: 'Bill',
stock: 'MSFT'
},
{
name: 'Bill',
stock: 'AAPL'
},
];
const result = Object.values(portfolio.reduce((res, {
stock,
name
}) => {
const existing = res[stock] || {
stock,
names: [],
count: 0
}
res[stock] = {
stock,
names: [...existing.names, name],
count: existing.count 1
}
return res
}, {}))
console.log(result)
CodePudding user response:
From the above comment ...
"What the OP wants is filtering and grouping array items (by a specific
key
) together with value aggregation of some/one other key/s. One usually would use areduce
based approach. One question though ... what is the additionalcount
value good for when one has this information already in any item'sitem.name.length
(or at least renamecount
tonameCount
)."
... used techniques/methods ...
const portfolio = [
{ name: 'Mark', stock: 'FB' },
{ name: 'Steve', stock: 'AAPL' },
{ name: 'Tim', stock: 'AAPL' },
{ name: 'Steve', stock: 'MSFT' },
{ name: 'Bill', stock: 'MSFT' },
{ name: 'Bill', stock: 'AAPL' },
];
const shareholderList = Object.values( // get only the values from ...
// ... create an index/map of stock specific shareholder items/objects
portfolio.reduce((stockIndex, { name, stock }) => {
// access an already existing object or
// create a new grouped (by `stock` value) to be merged and aggregated object.
const groupedMerger = (stockIndex[stock] ??= { stock, names: [], nameCount: 0 });
// aggregate list of `stock` specific shareholder names.
groupedMerger.names.push(name);
// increment count of `stock` specific shareholder names.
groupedMerger.nameCount;
// the programmatically built index/map of stock specific shareholder items/objects.
return stockIndex;
}, {})
).sort((a, b) => b.nameCount - a.nameCount); // sort shareholder items by theirs `nameCount`s.
console.log({ shareholderList });
.as-console-wrapper { min-height: 100%!important; top: 0; }
And in order to demonstrate how each part works and how everything works together, the above main approach will be compacted into a (re-usable) function statement.
function aggregateStockIndex(index, { name, stock }) {
const groupedMerger = (index[stock] ??= { stock, names: [], nameCount: 0 });
groupedMerger.names.push(name);
groupedMerger.nameCount;
return index;
}
const portfolio = [
{ name: 'Mark', stock: 'FB' },
{ name: 'Steve', stock: 'AAPL' },
{ name: 'Tim', stock: 'AAPL' },
{ name: 'Steve', stock: 'MSFT' },
{ name: 'Bill', stock: 'MSFT' },
{ name: 'Bill', stock: 'AAPL' },
];
const stockIndex = portfolio
.reduce(aggregateStockIndex, {});
const shareholderList = Object.values(
// stockIndex
portfolio.reduce(aggregateStockIndex, {})
).sort((a, b) => b.nameCount - a.nameCount);
console.log({
stockIndex,
shareholderList,
});
.as-console-wrapper { min-height: 100%!important; top: 0; }
CodePudding user response:
I shared a function named groupPortfolio
that takes a portfolio as an argument expecting to be a list of people holding a share of a stock.
The function first groups those people as a map binding each stock to which holders it belong to and eventually uses that map to create the final array as a list of stocks where each one has a list of people holding its share and the corresponding amount of people in that list.
function groupPortfolio(portfolio){
//groups the portfolio item in [stock] => shareholders[]
let grouped = {};
for(let o of portfolio){
if( !Object.keys(grouped).includes(o.stock) )
grouped[o.stock] = [];
grouped[o.stock].push( o.name );
}
//creates the shareholders array starting from the grouped stocks
let shareholders = [];
for( let stockGroup of Object.keys(grouped) ){
shareholders.push(
{ stock: stockGroup, name: grouped[stockGroup], count: grouped[stockGroup].length }
);
}
return shareholders;
}
const portfolio1 = [
{name: 'Mark', stock: 'FB'},
{name: 'Steve', stock: 'AAPL'},
{name: 'Tim', stock: 'AAPL'},
{name: 'Steve', stock: 'MSFT'},
{name: 'Bill', stock: 'MSFT'},
{name: 'Bill', stock: 'AAPL'},
];
let shareholder1 = groupPortfolio(portfolio1);
console.log( shareholder1 );
/*
0:
stock: "FB"
name: ['Mark']
count: 1
1:
stock: "AAPL"
name: (3) ['Steve', 'Tim', 'Bill']
count: 3
2:
stock: "MSFT"
name: (2) ['Steve', 'Bill']
count: 2
*/
CodePudding user response:
You can use two simple for loops
to convert the first array
into the second array
.
Working Example:
const portfolio = [
{name: 'Mark', stock: 'FB'},
{name: 'Steve', stock: 'AAPL'},
{name: 'Tim', stock: 'AAPL'},
{name: 'Steve', stock: 'MSFT'},
{name: 'Bill', stock: 'MSFT'},
{name: 'Bill', stock: 'AAPL'},
];
let shareholder = [];
// CYCLE THROUGH PORTFOLIO
for (let i = 0; i < portfolio.length; i ) {
// DETERMINE IF STOCK ENTRY ALREADY EXISTS
let stockIndex = shareholder.length;
for (let j = 0; j < shareholder.length; j ) {
if (portfolio[i].stock === shareholder[j].stock) {
stockIndex = j;
}
}
// ADD NEW ENTRY IF STOCK ENTRY DOES NOT EXIST
if (stockIndex === shareholder.length) {
shareholder[stockIndex] = {stock: portfolio[i].stock, name: [], count: 0};
}
// ADD DETAILS TO NEW OR EXISTING STOCK ENTRY
shareholder[stockIndex].name.push(portfolio[i].name);
shareholder[stockIndex].count ;
}
console.log(shareholder);
CodePudding user response:
You could achieve this in two steps
- First create an object with
stock
as the key name to find out all the records with unique stock. - Loop over the object created in step#1 to convert to an Array structure
I couldn't think of ay solution which could achieve it in single iteration.
Please see the code snippet below.
const portfolio = [
{name: 'Mark', stock: 'FB'},
{name: 'Steve', stock: 'AAPL'},
{name: 'Tim', stock: 'AAPL'},
{name: 'Steve', stock: 'MSFT'},
{name: 'Bill', stock: 'MSFT'},
{name: 'Bill', stock: 'AAPL'},
];
let shareholderObj = {};
let shareholderArr = [];
portfolio.forEach((el) => {
const stock = el.stock
if(shareholderObj[stock]){
shareholderObj[stock].name.push(el.name)
}
else{
shareholderObj[stock] = {
name: [el.name]
}
}
})
for (let [key, value] of Object.entries(shareholderObj)) {
shareholderArr.push({
stock: key,
name: value.name,
count: value.name.length
})
}
console.log(shareholderArr)