Merge 2 arrays keeping inner elements array values - javascript

I'm trying to merge 2 objects which contains arrays in one of their elements. I don't achieve the disered result when using spread syntax and the first object array is being replaced by the second one. The objects are like the following:
const objectA1 = {
keyA1:'valueA1',
keyArr:[{
arrKeyA01:'arrValueA01',
arrKeyA02:'arrValueA02',
},
{
arrKeyA11:'arrValueA11',
arrKeyA12:'arrValueA12',
}
]
}
const objectB1 = {
keyB1:'valueB1',
keyArr:[{
arrKeyB01:'arrValueB01',
arrKeyB02:'arrValueB02',
},
{
arrKeyB11:'arrValueB11',
arrKeyB12:'arrValueB12',
}
]
}
And I want to get:
const objectRes = {
keyA1:'valueA1',
keyB1:'valueB1',
keyArr:[{
arrKeyA01:'arrValueA01',
arrKeyA02:'arrValueA02',
arrKeyB01:'arrValueB01',
arrKeyB02:'arrValueB02',
},
{
arrKeyA11:'arrValueA11',
arrKeyA12:'arrValueA12',
arrKeyB11:'arrValueB11',
arrKeyB12:'arrValueB12',
}
]
}
What I'm using is
{...objectA1 ,...objectB1}
But as said, the keyArr doesn't keep the objectA1 elements.
How I can merge both objects and keep the array data using spread syntax?
Thanks for any comment/help :)

Create an object and place the first 2 values from A1 and B2 object. Customize the array separately by using reduce
const objectA1 = {
keyA1: 'valueA1',
keyArr: [{
arrKeyA01: 'arrValueA01',
arrKeyA02: 'arrValueA02',
},
{
arrKeyA11: 'arrValueA11',
arrKeyA12: 'arrValueA12',
}
]
}
const objectB1 = {
keyB1: 'valueB1',
keyArr: [{
arrKeyB01: 'arrValueB01',
arrKeyB02: 'arrValueB02',
},
{
arrKeyB11: 'arrValueB11',
arrKeyB12: 'arrValueB12',
}
]
}
const arr = objectA1.keyArr.reduce((acc, x) => {
const res1 = objectB1.keyArr.reduce((acc2, y) => ({...x,...y}), {})
return acc = [...acc, res1];
}, [])
const result = {
keyA1: objectA1.keyA1,
keyB1: objectB1.keyB1,
keyArr: arr
}
console.log(result)

I wanted to share my attemp solving this problem, I take the array and merge it in one using loops:
const objectA1 = {
keyA1:'valueA1',
keyArr:[{
arrKeyA01:'arrValueA01',
arrKeyA02:'arrValueA02',
},
{
arrKeyA11:'arrValueA11',
arrKeyA12:'arrValueA12',
}
]
}
const objectB1 = {
keyB1:'valueB1',
keyArr:[{
arrKeyB01:'arrValueB01',
arrKeyB02:'arrValueB02',
},
{
arrKeyB11:'arrValueB11',
arrKeyB12:'arrValueB12',
}
]
}
objects = [objectA1, objectB1];
let i = 0;
new_array = {};
for(i; i < objects.length; i++){
object = objects[i];
keys = Object.keys(object);
for(j = 0; j < keys.length; j++){
//if property already exists, example keyArr
this_key = keys[j];
console.log(this_key);
if(new_array[this_key] != undefined){
//loop through that property in the object
object[this_key].forEach((object_value, index) => {
//add all properties that previous object did not have
Object.assign(new_array[this_key][index], object_value);
});
}else{
//initialize that value with the first element array
new_array[this_key] = object[this_key];
}
}
}
console.log(objects);
console.log(new_array);

Related

How to dynamically append key/values to a nested object

I am trying to append to an object/dictionary of sorts that adds categories and subcategories as they are found. However, each time I try to add them it seems like I just get the last element added to the nested object and overwrites the previous additions. I've tried using Object.assign() and {...obj, key:value} to no avail.
I have multiple for-loops that independently add each key:value pair after the database has been queried.
I am looking to create an object resembling this:
{
category1: {
subcategory1: null,
subcategory2: null,
subcategory3: {
microcategory1: null
}
},
category2: {
subcategory1: null,
subcategory2: null,
subcategory3: null
}
}
But am getting this instead:
{
cooking: {
'ranges': null
},
sinks: {
'filters': null
}
}
There should be 10+ subcategories for both cooking and sinks.
This is the code as it stands:
let categoriesDictObj = {};
for (var index = 0; index < categories.length; index++) {
let category = categories[index];
const subCategories = await Product.find({
productCategory: category,
}).distinct("productSubCategory");
for (
var subCatIndex = 0; subCatIndex < subCategories.length; subCatIndex++
) {
let subCategory = subCategories[subCatIndex];
const microCategories = await Product.find({
productMicroCategory: subCategory,
}).distinct("productMicroCategory");
// categoriesDictObj[category] = { [subCategory]: null };
// Object.assign(categoriesDictObj, {
// [category]: { [subCategory]: null },
// });
categoriesDictObj = {
...categoriesDictObj,
[category]: {
[subCategory]: subCatIndex
},
};
}
}
You're missing to spread the previous categoriesDictObj[category] in the inner object, otherwise you're always overwriting the category object with a completely new one and only the last (with a single subCategory key) will prevail.
categoriesDictObj = {
...categoriesDictObj,
[category]: {
...categoriesDictObj[category],
[subCategory]: subCatIndex
},
};
However, there's no need to make it that complicated. Just create the inner object, fill it in the inner loop, and then assign it as part of the categoriesDictObj in the outer loop:
const categories = …;
const categoriesDictObj = {};
for (let index = 0; index < categories.length; index++) {
const category = categories[index];
const subCategories = …;
const subCategoriesDictObj = {};
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
for (let subCatIndex = 0; subCatIndex < subCategories.length; subCatIndex++) {
const subCategory = subCategories[subCatIndex];
const microCategories = …;
subCategoriesDictObj[subCategory] = subCatIndex;
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
}
categoriesDictObj[category] = subCategoriesDictObj;
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
}
You could also make the variables mutable and keep the objects immutable by replacing the subCategoriesDictObj[subCategory] assignment with
subCategoriesDictObj = {
...subCategoriesDictObj,
[subCategory]: subCatIndex
};
and the categoriesDictObj[category] asssignment with
categoriesDictObj = {
...categoriesDictObj,
[category]: subCategoriesDictObj
};
but that's really just pointless inefficiency.

Transform array into object with custom properties

I have this array
myarr = [
'=title1',
'longText0...',
'longtText1...',
'=title2',
'longTextA...',
'longtTextB...',
'longtTextC...'
];
symbol = indicates that is is a property, next to that is a list of items that belongs to that property
I want to transform that array into object
myObj = {
title1: [
'longText0...',
'longtText1...',
],
title2: [
'longTextA...',
'longtTextB...',
'longtTextC...'
]
}
I come up with this code so far:
const arrayToObject = (array) =>
array.reduce((obj, item) => {
if(item.startsWith('=')) {
const itemName = item.replace('=', '')
obj[itemName] = itemName;
} else {
//add the rest....
}
return obj
}, {})
console.log(arrayToObject(myarr))
My challenges so far is that I am not sure how to turn obj[itemName] so I can assign the items to it. Any ideas how to do that?
A reduce based approach which does not depend on outer scope references for keeping track of the currently to be built/aggregated property makes this information part of the reducer function's first parameter, the previousValue which serves as an accumulator/collector object.
Thus, as for the OP's task, this collector would feature two properties, the currentKey and the result, where the former holds the state of the currently processed property name and the latter being the programmatically built result.
// - reducer function which aggregates entries at time,
// either by creating a new property or by pushing a
// value into the currently processed property value.
// - keeps the state of the currently processed property
// by the accumulator`s/collector's `currentKey` property
// whereas the result programmatically gets build as
// the accumulator`s/collector's `result` property.
function aggregateEntry({ currentKey = null, result = {} }, item) {
const key = (item.startsWith('=') && item.slice(1));
if (
(key !== false) &&
(key !== currentKey)
) {
// keep track of the currently processed property name.
currentKey = key;
// create a new entry (key value pair).
result[currentKey] = [];
} else {
// push value into the currently processed property value.
result[currentKey].push(item);
}
return { currentKey, result };
}
console.log([
'=title1',
'longText0...',
'longtText1...',
'=title2',
'longTextA...',
'longtTextB...',
'longtTextC...',
].reduce(aggregateEntry, { result: {} }).result);
.as-console-wrapper { min-height: 100%!important; top: 0; }
I wouldn't do that with reduce but with a simple for loop, because you have to carry the itemname over multiple iterations
let o = {}, n = '';
for (let k of arr) {
if (k.startsWith('=')) {
n = k.substring(1);
o[n] = []
} else {
o[n].push(k);
}
}
You can of course also do it with reduce, but you have to put the declaration of itemname outside of the callback
let n = '';
let o = arr.reduce((a, c) => {
if (c.startsWith('=')) {
n = c.substring(1);
a[n] = [];
} else {
a[n].push(c);
}
return a;
}, {});
Please be aware, there is no error handling, ie the code assumes your array is well structured and the first element in the array must start with =
The following function will give you the desired results
function arrayToObject(arr)
{
let returnObj={};
for(let i =0; i <arr.length; i++)
{
if(arr[i].startsWith('='))
{
let itemName = arr[i].replace('=','');
returnObj[itemName]=[];
for(let j=i+1; j <arr.length;j++)
{
if(arr[j].startsWith('='))
{
break;
}
else
{
let value = arr[j];
returnObj[itemName].push(value) ;
}
}
}
}
return returnObj;
}
Here a version with reduce
const myarr = [
'=title1',
'longText0...',
'longtText1...',
'=title2',
'longTextA...',
'longtTextB...',
'longtTextC...'
];
const obj = myarr.reduce((res, el) => {
if(el.startsWith('=')){
const key = el.substring(1)
return {
data: {
...res.data,
[key]: [],
},
key
}
}
return {
...res,
data:{
...res.data,
[res.key]: [...res.data[res.key], el]
}
}
}, {
data: {},
key: ''
}).data
console.log(obj)
You don't need to keep the key somewhere separate for a reduce method:
const myarr = ['=title1', 'longText0...', 'longtText1...', '=title2', 'longTextA...', 'longtTextB...', 'longtTextC...'];
const res = Object.fromEntries(
myarr.reduce((acc, item) => {
if(item.startsWith('='))
acc.push([item.substring(1), []]);
else
acc[acc.length - 1]?.[1].push(item);
return acc;
}, [])
);
console.log(JSON.stringify( res ));

What's a better algorithm to remove duplicates from an array of objects?

I have an array of objects that looks something like (rough example):
[{id:1, stuff:moreStuff}, {id:6, manyStuff,Stuffing}, {id:4, yayStuff, stuff}, {id:6, manyStuff, Stuffing}]
The problem is that in the array, there are several duplicate objects. The current solution I've thought of so far is something along the lines of this:
const DuplicateCheck = []
const FinalResult = []
for (let i = 0; i < ArrayOfObjects.length; i++) {
let isPresent = false;
for (let j = 0; j < duplicateCheck.length; j++) {
if (ArrayOfObjects[i].id == duplicateCheck[j]) {
isPresent = true;
}
}
if (isPresent = false) {
DuplicateCheck.push(ArrayOfObjects[i].id
FinalResult.push(ArrayOfObjects[i]
}
}
Now after learning big O, it seems like this is a very inefficient way to go about doing this problem. So my question is, is there a better, more efficient way to solve this problem?
Yes, use a Set for your DuplicateCheck which gives you O(1) access by id:
const duplicateCheck = new Set
const finalResult = []
for (const object of arrayOfObjects) {
if (!duplicateCheck.has(object.id)) {
duplicateCheck.add(object.id)
finalResult.push(object)
}
}
You could iterate over the array and store the id in and object (hash table) and then check if exist. Something like:
const DuplicateCheck = {}
const FinalResult = []
for (let i = 0; i < ArrayOfObjects.length; i++) {
let currentId = ArrayOfObjects[i].id
if (!DuplicateCheck[currentId]) {
DuplicateCheck[currentId] = 1
FinalResult.push(ArrayOfObjects[i])
}
}
And you will receive all unique objects in the FinalResult
You could keep usedIds as object properties and add to the filtered array only if the object has no such property or just add your items in Set if that's a possibility for you. Set as a data structure can only store non-duplicates.
Without Set:
const filteredArray = [];
const usedIds = {};
for (const item of array) {
if (!usedIds[item.id]) {
usedIds[item.id] = true;
filteredArray.push(item);
}
}
With Set:
const filteredArray = [];
const usedIds = new Set();
for (const item of array) {
if (!usedIds.has(item.id)) {
usedIds.add(item.id);
filteredArray.push(item);
}
}
Runnable example:
const array = [
{
id: 1,
stuff: 'stuff',
moreStuff: 'moreStuff'
},
{
id: 6,
manyStuff: 'manyStuff',
stuffing: 'stuffing'
},
{
id: 4,
yayStuff: 'yayStuff',
stuff: 'stuff'
},
{
id: 6,
manyStuff: 'manyStuff',
stuffing: 'stuffing'
}
];
const filteredArray = [];
const usedIds = {};
for (const item of array) {
if (!usedIds[item.id]) {
usedIds[item.id] = true;
filteredArray.push(item);
}
}
console.log(filteredArray);
You can also use a Map to filter out duplicates. Contrary to the Set approach by Bergi this solution leaves the last version of the duplicate, since it overrides the key/value-pair with the same key.
const objectsById = new Map(arrayOfObjects.map(object => [object.id, object]));
const finalResult = Array.from(objectsById.values());
The code above does need to iterate the collection 2 times. Once using map to create key/value-pairs and once when the created array is converted to a Map.
When the resulting objectsById is created we'll have to iterate over the values to convert them back to array.
In total this means between 2 and 3 iterations over the full collection, which more often then not still a lot faster then solutions using find. Since that iterates over the array every time it is called.
You can reduce the amount of iterations by 1 if you omit the map call and manually insert the elements in objectsById:
const objectsById = new Map();
for (const object of arrayOfObjects) {
objectsById.set(object.id, object);
}

How to convert an array into a hierarchical array

I have some data which is
var currentData = [
{'ticket':'CAP', 'child':'CT-1'},
{'ticket':'CAP', 'child':'CT-2'},
{'ticket':'CT-1', 'child':'CT-1-A'},
{'ticket':'CT-1', 'child':'CT-1-B'}
];
The data is flat and I need to convert it into something like:
{
'ticket': 'CAP',
children : [{
'ticket' : 'CT-1',
'children' : [{
'ticket' : 'CT-1-A',
'children' : []
}, {
'ticket' : 'CT-1-B',
'children' : []
}],
[{
'ticket' : 'CT-2',
'children' : []
}]
}]
}
(I think the above is valid)?
I'm very lost as to how. I am going to show my effort but, I'm not sure if my approach is correct or not.
var currentData = [{'ticket':'cap', 'child':'CT-1'},{'ticket':'cap', 'child':'CT-2'}, {'ticket':'CT-1', 'child':'CT-1-A'},{'ticket':'CT-1', 'child':'CT-1-B'}];
var newList = [];
function convert(list){
if (newList.length <= 0){
var child = [];
var emptyChild = [];
child.push({'ticket': list[0].child, 'child': emptyChild });
newList.push({'ticket': list[0].ticket, 'children' : child});
list.splice(0,1);
} // the if statement above works fine
for(var i = 0; i < list.length; i++) {
var ticket = list[i].ticket;
for(var j = 0; j < newList.length; j++) {
if (newList[j].ticket == ticket){
var child;
var emptyChild = [];
child = {'ticket': list[i].child, 'child': emptyChild };
newList[j].children.push(child);
list.splice(i,1);
break;
} // the if above works
else{
var child2 = getFromChildren(ticket, newList, list[i]); // child2 is Always null, even if getFromChildren returns an object
newList[j].children.push(child2);
list.splice(i,1);
break;
}
}
}
if (list.length > 0){
convert(list);
}
}
function getFromChildren(ticket, list, itemToAdd){
if (list == null || list[0].children == null)
return;
for(var i = 0; i < list.length; i++) {
if (list[i] == null)
return;
if (list[i].ticket == ticket){
list[i].child.push(itemToAdd.child); // ** can't do this, javascript passes by value, not by reference :(
} else{
getFromChildren(ticket, list[i].children, itemToAdd);
}
}
}
convert(currentData);
I think I've made a mess of it. In the comments I've put a ** explaining that it isn't working due to JavaScript not passing by reference, however upon further reading I don't think that is correct as I'm passing the object which is by reference?
Edit
The data, shown with currentData will not always start at the root sadly either
function convert(arr) {
var children = {}; // this object will hold a reference to all children arrays
var res = arr.reduce(function(res, o) { // for each object o in the array arr
if(!res[o.ticket]) { // if there is no object for the element o.ticket
res[o.ticket] = {ticket: o.ticket, children: []}; // then creates an object for it
children[o.ticket] = res[o.ticket].children; // and store a reference to its children array
}
if(!res[o.child]) { // if there is no object for the element o.child
res[o.child] = {ticket: o.child, children: []}; // then creates an object for it
children[o.child] = res[o.child].children; // and store a reference to its children array
}
return res;
}, {});
arr.forEach(function(o) { // now for each object o in the array arr
children[o.ticket].push(res[o.child]); // add the object of o.child (from res) to its children array
delete res[o.child]; // and remove the child object from the object res
});
return res;
}
var currentData = [
{'ticket':'CAP', 'child':'CT-1'},
{'ticket':'CAP', 'child':'CT-2'},
{'ticket':'CT-1', 'child':'CT-1-A'},
{'ticket':'CT-1', 'child':'CT-1-B'}
];
console.log(convert(currentData));
Explanation:
The reduce part creates an object of the form: { ticket: "...", children: [] } for each element (child or not). So right after reduce, the object res will be:
res = {
'CAP': { ticket: 'CAP', children: [] },
'CT-1': { ticket: 'CT-1', children: [] },
'CT-2': { ticket: 'CT-2', children: [] },
'CT-1-A': { ticket: 'CT-1-A', children: [] },
'CT-1-B': { ticket: 'CT-1-B', children: [] },
}
Now comes the forEach bit which loops over the array once more, and now for each object it fetches the object of .child from res above, push it into .ticket object's children (which a reference to it is stored in children object), then remove the .child object from the object res.
Below uses reduce to get the data grouped to a Map, then I convert the data to an object like you've shown above. You'll need a modern browser to run below snippet, or use a transpiler like babeljs to convert it to es5 syntax.
let currentData = [
{'ticket':'CAP', 'child':'CT-1'},
{'ticket':'CAP', 'child':'CT-2'},
{'ticket':'CT-1', 'child':'CT-1-A'},
{'ticket':'CT-1', 'child':'CT-1-B'}
];
let children = currentData.map(e => e.child);
currentData.sort((a,b) => children.indexOf(a.ticket));
let res = currentData.reduce((a,b) => {
if (! children.includes(b.ticket)) {
return a.set(b.ticket, (a.get(b.ticket) || [])
.concat({ticket: b.child,
children: currentData
.filter(el => el.ticket === b.child)
.map(el => ({ticket: el.child, children: []}))}))
}
return a;
}, new Map);
let r = {};
for (let [key,value] of res.entries()) {
r.ticket = key;
r.children = value;
}
console.log(r);
Solution using recursion, starting node can be changed.
var currentData = [{'ticket': 'cap','child': 'CT-1'}, {'ticket': 'cap','child': 'CT-2'}, {'ticket': 'CT-1','child': 'CT-1-A'}, {'ticket': 'CT-1','child': 'CT-1-B'}];
function convert(data, start){
return {
ticket: start,
childs: data.filter(d => d.ticket == start)
.reduce((curr, next) => curr.concat([next.child]), [])
.map(c => convert(data, c))
}
}
let result = convert(currentData, 'cap');
console.log(result);
.as-console-wrapper{top: 0; max-height: none!important;}
I would go with a simple for approach, like this:
var currentData = [
{'ticket':'CAP', 'child':'CT-1'},
{'ticket':'CAP', 'child':'CT-2'},
{'ticket':'CT-1', 'child':'CT-1-A'},
{'ticket':'CT-1', 'child':'CT-1-B'}
];
var leafs = {};
var roots = {};
var tickets = {};
for(var i=0; i<currentData.length; i++){
var ticket = currentData[i].ticket;
var child = currentData[i].child;
if(!tickets[ticket]){
tickets[ticket] = {ticket:ticket,children:[]};
if(!leafs[ticket]){
roots[ticket] = true;
}
}
if(!tickets[child]){
tickets[child] = {ticket:child,children:[]};
}
delete roots[child];
leafs[child] = true;
tickets[ticket].children.push(tickets[child]);
}
for(var ticket in roots){
console.log(tickets[ticket]);
}
Well, if you are not familiar with reduce, map , forEach with callbacks to iterate, then here is a approach I came with, where the code is flat, storing object references in another map object and iterating exactly once the source array.
The code is much cleaner, if something is understandable add comments I will explain;
var currentData = [
{'ticket':'CT-1', 'child':'CT-1-A'},
{'ticket':'CT-1', 'child':'CT-1-B'},
{'ticket':'CAP', 'child':'CT-1'},
{'ticket':'CAP', 'child':'CT-2'}
];
function buildHierarchy(flatArr) {
let root = {},
nonRoot = {},
tempMap = {};
Object.setPrototypeOf(root, nonRoot);
for (let idx = 0; idx < flatArr.length; idx++) {
let currTicket = flatArr[idx];
let tempTicket = tempMap[currTicket.ticket] || {ticket: currTicket.ticket, children: []};
tempMap[currTicket.ticket] = tempTicket;
if (currTicket.child) {
let tempChild = tempMap[currTicket.child] || {ticket: currTicket.child, children: []};
tempTicket.children.push(tempChild);
tempMap[currTicket.child] = tempChild;
delete root[tempChild.ticket];
nonRoot[tempChild.ticket] = true;
}
root[tempTicket.ticket] = true;
}
return tempMap[Object.keys(root)[0]];
}
console.log(buildHierarchy(currentData));
I have changed the sequence of your source array in order to put the root object anywhere, and the code should work on that.

JavaScript - find unique values in array of objects, with count and create a new array of objects

I have an array of objects as below:
var arr =[
{
price:20,
rule:a
},
{
price:10,
rule:b
},
{
price:5,
rule:a
},
{
price:50,
rule:b
},
{
price:70,
rule:b
}
]
I want to extract an array of objects out of this as below:
var filteredArr = [
{
rule:a,
countOfRule:2,
minPriceForThisRule:5
},
{
rule:b,
countOfRule:3,
minPriceForThisRule:10
}
]
This means:
1) I want to create new array with no. of objects as unique no. of rules in first array "arr"
2) Need to count the unique rule repetition and add as property in new array objects - given as "countOfRule"
3) Find the minimum price for in a category of unique rule - given as "minPriceForThisRule"
I have read similar answers on SO and was able to get first 2 conditions only, and that too were not in the format as i need.
What I tried, referring to links on SO:
var ff = {},e;
for (var i = 0,l=arr.length; i < l; i++) {
e = arr[i];
ff[e.rule] = (ff[e.rule] || 0) + 1;
}
But this gives only a single object as
{
a : 2,
b: 3
}
You can do this with forEach and thisArg optional parameter.
var arr = [{"price":20,"rule":"a"},{"price":10,"rule":"b"},{"price":5,"rule":"a"},{"price":50,"rule":"b"},{"price":70,"rule":"b"}],
r = [];
arr.forEach(function(e) {
if(!this[e.rule]) {
this[e.rule] = {rule: e.rule, countOfRule: 0, minPriceForThisRule: e.price}
r.push(this[e.rule]);
}
this[e.rule].countOfRule++;
if(this[e.rule].minPriceForThisRule > e.price) this[e.rule].minPriceForThisRule = e.price;
}, {});
console.log(r)
I would use reduce. Something like:
var reduced = arr.reduce(function(memo, obj){
var rule = memo[obj.rule];
rule.countOfRule++;
if(!rule.minPriceForThisRule){
rule.minPriceForThisRule = obj.price;
} else{
if(obj.price < rule.minPriceForThisRule){
rule.minPriceForThisRule = obj.price;
}
}
return memo;
}, map);
where the initial map looks like:
var map = {
1: {
rule: 1,
countOfRule: 0,
minPriceForThisRule: null
},
2: {
rule: 2,
countOfRule: 0,
minPriceForThisRule: null
}
}
Of course you could dynamically create the map if needed.
https://plnkr.co/edit/wLw3tEx2SMXmYE7yOEHg?p=preview
This is how i would do this job,
var arr =[
{
price:20,
rule:"a"
},
{
price:10,
rule:"b"
},
{
price:5,
rule:"a"
},
{
price:50,
rule:"b"
},
{
price:70,
rule:"b"
}
],
reduced = arr.reduce((p,c) => { var fo = p.find(f => f.rule == c.rule);
fo ? (fo.countOfRule++,
fo.minPriceForThisRule > c.price && (fo.minPriceForThisRule = c.price))
: p.push({rule:c.rule, countOfRule:1, minPriceForThisRule: c.price});
return p;
},[]);
console.log(reduced);
Arrows might not work at IE or Safari. If that would be a problem please replace them with their conventional counterparts.

Categories

Resources