Split array to include smaller ones based on id - javascript

I have an example array:
arr = [{id:1, count: 2}, {id: 2, count: 6}, {id: 2, count: 4}, {id: 1, count:4}]
I need transform it to include arrays with objects inside based on id:
[[{id:1, count: 2}, {id: 1, count:4}], [{id: 2, count: 6}, {id: 2, count: 4}]]
If I will have 3 different ids - then it will have 3 arrays inside and so on.
If you know any good solutions - let me know. Lodash could be ok as well.

You can use groupBy from lodash to get a map like this:
{
'1': [{id:1, count: 2}, {id: 1, count:4}],
'2': [{id: 2, count: 6}, {id: 2, count: 4}]]
}
Then you can transform it to an array using Object.values()
Essentially you need these two lines:
const groupedById = _.groupBy(items, item => item.id);
const result = Object.values(groupedById);

Pure JS, with reduce:
arr.reduce((acc, curr) => {
let existing = acc.findIndex(elem => elem.some(obj => obj.id === curr.id));
if (existing > -1) {
acc[existing].push(curr);
}
else {
acc[acc.length] = [curr]
}
return acc;
}, []);

As you mentioned in your question lodash solution could also work for you, then loadash has one out of the box method groupBy which can achieve your desired result.
import { groupBy } from "lodash";
const arr = [{id:1, count: 2}, {id: 2, count: 6}, {id: 2, count: 4}, {id: 1, count:4}]
const result = groupBy(arr, 'id');
console.log(result)
Working DEMO

#domenikk showed a really good example! Also, you could use Ramda instead of Lodash to have a point-free function =)
const arr = [
{id:1, count: 2},
{id: 2, count: 6},
{id: 2, count: 4},
{id: 1, count:4}
]
const groupById = R.compose(
R.values,
R.groupBy(R.prop('id'))
)
console.log(groupById(arr))
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.25.0/ramda.min.js"></script>

Related

display entire array after moving values of it to another array

I have an array containing objects where there is a rpId key in some of the objects. The goal is to separate/move the objects that return undefined to a separate array and remove them out of the first array.
e.g.:
results = [{id: 1}, {id: 2, rpId: 1076}, {id: 3}, {id: 4, rpId: 303}];
goal: results = [{id: 2, rpId: 1076}, {id: 4, rpId: 303}] and stations = [{id: 1}, {id: 3}]
My current approach can be seen below. As visible, I get a wrong array1 because it contains an object with a rpId, plus array2 returns the keys of the object and I'd like to read the entire object, not just the "undefined" of the key.
const array1 = [{id: 1}, {id: 2, rpId: 1076}, {id: 3}, {id: 4, rpId: 303}];
const array2 = [];
const mapping = array1.map((e) => e.rpId);
console.log("mapping",mapping);
mapping.forEach(function(elem, index){
elem === undefined ? array2.push(elem) && array1.splice(index, elem === undefined) && console.log(elem): console.log("defined", elem);
}),
console.log("1", array1); // [{ id: 2, rpId: 1076 }, { id: 3 }]
console.log("2", array2); // [undefined, undefined]
Just check if the rpId property is undefined in each element.
const array1 = [{id: 1}, {id: 2, rpId: 1076}, {id: 3}, {id: 4, rpId: 303}];
const array2 = [];
array1.forEach(function(elem, index){
if(elem.rpId === undefined)
array2.push(elem) && array1.splice(index, 1)
});
console.log(array1);
console.log(array2);
One can also use Array#filter or push elements into two separate arrays based on the condition for better performance.
const array1 = [{id: 1}, {id: 2, rpId: 1076}, {id: 3}, {id: 4, rpId: 303}];
const yes = [], no = [];
array1.forEach(elem=>(elem.rpId!==undefined?yes:no).push(elem));
console.log(yes);
console.log(no);
You can use filter too:
let results = [
{ id: 1 },
{ id: 2, rpId: 1076 },
{ id: 3 },
{ id: 4, rpId: 303 },
];
const stations = results.filter((c) => !c.rpId);
results = results.filter((c) => c.rpId);
console.log("stations", stations);
console.log("results", results);
const GiveItACreativeName = (arr) => {
const result = []
const stations = []
arr.forEach((el) => {
if('rpId' in el) result.push(el);
else stations.push(el);
});
return {result, stations}
}
console.log(
GiveItACreativeName([{id: 1}, {id: 2, rpId: 1076}, {id: 3}, {id: 4, rpId: 303}])
);

JavaScript sort ascending or descending order values in object base on sub object value

I have product object. every product i have price sub object. Inside price object can have multiple values. I want to sort price object base on original_price and then entire product object base on price.
e.g
[
{product: 1,
price[
{id: 1, original_price: 18},
{id: 2, original_price: 10}
]
},
{product: 2,
price[
{id: 1, original_price: 12},
{id: 2, original_price: 15},
{id:3, original_price: 5}
]
}
]
After sort
[
{product: 2,
price[
{id: 3, original_price: 5},
{id: 1, original_price: 12},
{id: 2, original_price: 15}
]
}
{product: 1,
price[
{id: 2, original_price: 10},
{id: 1, original_price: 18}
]
}
]
can someone help me to fix this?
Need to sort both ways (ascending or descending)
Making the assumption that you will be sorting based on product and original_price, you could do this.
function sortAscendingPrice(a, b) {
return a.original_price - b.original_price;
}
function sortDescendingPrice(a, b) {
return b.original_price - a.original_price;
}
function sortAscendingProduct(a, b) {
return a.product - b.product;
}
function sortDescendingProduct(a, b) {
return b.product - a.product;
}
const data = [
{
product: 1,
price: [
{id: 1, original_price: 18},
{id: 2, original_price: 10}
]
},
{
product: 2,
price: [
{id: 1, original_price: 12},
{id: 2, original_price: 15},
{id:3, original_price: 5}
]
}
];
const sortedData = data
.map(el => {
return {
product: el.product,
price: el.price.sort(sortAscendingPrice)
};
})
.sort(sortDescendingProduct);
This will sort your data the way that you are expecting it to be sorted. If you wanted to sort ascending/descending you would just switch out the function that you pass in to your sort when needed. I've provided both ascending and descending functions in this example even though they are not all being used.
More information about sorting arrays can be found here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort

how get common elements of 2 different arrays and return an object containing the common elements

I have 2 arrays of objects
var array1 = [
{id: 1, name:'fruit', rating:5},
{id: 4, name:'vegetable', rating: 3},
{id: 8, name:'meat', rating:1}
];
var array2 = [
{alimentId: 1, quantity: 2},
{alimentId: 4, quantity: 2},
{alimentId: 8, quantity: 4}
]
and I want to get a new the array1 such that
var array = [
{id: 1, name:'fruit'},
{id: 4, name:'vegetable'},
]
which has only the elements with quantity 2 matching the alimentId with the id.
I'm always getting confused with arrays and objects manipulations.. Please help
I believe the following code will solve your problem:
const func = (arr1, arr2) => {
return arr1.filter(obj => {
const objToCheck = arr2.filter(element => element.alimentId === obj.id);
return objToCheck[0].quantity === 2;
});
};
You also can send the wanted value(2) and the key name(quantity) as params.
var array1 = [
{id: 1, name:'fruit', rating:5},
{id: 4, name:'vegetable', rating: 3},
{id: 8, name:'meat', rating:1}
];
var array2 = [
{alimentId: 1, quantity: 2},
{alimentId: 4, quantity: 2},
{alimentId: 8, quantity: 4}
]
function filter(array1, array2) {
return array1
.filter(it => array2 // filter array1 by array2
.filter(it => it.quantity === 2) // filter your array2 by field quantity = 2
.map(it => it.alimentId) // pull out array of alimentId
.includes(it.id) // check array2.alimentId includes array1.id
)
}
console.log(filter(array1, array2))
use this function
const common_elements = (arr1, arr2, quantity) => {
let res = []
arr1.forEach(el1 => {
arr2.forEach(el2 => {
if(el1.id === el2.alimentId && el2.quantity === quantity) {
res.push(el1)
}
});
});
return res
}
You can do a reduce:
var array3 = array1.reduce((acc ,val ,index) => {
if (val.id=array2[index].alimentId) {
acc =[...acc, {id: val.id, name: val.name}]
}
return acc;
},[]);
var array1 = [
{id: 1, name:'fruit', rating:5},
{id: 4, name:'vegetable', rating: 3},
{id: 8, name:'meat', rating:1}
];
var array2 = [
{alimentId: 1, quantity: 2},
{alimentId: 4, quantity: 2},
{alimentId: 8, quantity: 4}
]
const commonArray = array2.filter(item => item.quantity === 2 && array1.find(el => el.id===item.alimentId));
console.log(commonArray)

Get maximum values of property from array of objects by id [duplicate]

This question already has answers here:
JavaScript "new Array(n)" and "Array.prototype.map" weirdness
(14 answers)
Closed 4 years ago.
I have an array of objects that looks like this:
const input = [
{id: 3, value: 2},
{id: 0, value: 3},
{id: 2, value: 8},
{id: 1, value: 5},
{id: 0, value: 2},
{id: 1, value: 6}
]
And I am trying to build an array of the maximum value by id, with id as index. For our example the desired output is the following:
const output = [ 3, 6, 8, 2 ]
I am also assuming that I know the number of unique ids ahead of time, and that they start at 0 and rise sequentially. My first whack at this was to .map() over the an empty array of the right length and build intermediate arrays with .filter() for each id, then use Math.max() on the filtered arrays.
const myAttempt = Array(4).map((_, index) => {
const filtered = input.filter(item => item.id === index);
return Math.max(filtered);
});
All I get out of this is:
myAttempt = [ 4 empty slots ];
I suspect I'm totally off-base with the Array(4) bit, and that the answer might involve .reduce(), but I never really got the hang of reduce so any help would be very much appreciated.
PS: I'd prefer answers that avoid the use of libraries in the vein of lodash or jQuery.
Use Array.reduce() to collect the values highest value of each key. Convert to array using Array.values():
const input = [
{id: 3, value: 2},
{id: 0, value: 3},
{id: 2, value: 8},
{id: 1, value: 5},
{id: 0, value: 2},
{id: 1, value: 6}
]
const result = Object.values(input.reduce((r, { id, value }) => {
r[id] = +r[id] > value ? r[id] : value;
return r;
}, {}));
console.log(result);
If all ids from 0 on wards appear in the array, you can add the values by their id (index) to an array accumulator:
const input = [
{id: 3, value: 2},
{id: 0, value: 3},
{id: 2, value: 8},
{id: 1, value: 5},
{id: 0, value: 2},
{id: 1, value: 6}
]
const result = input.reduce((r, { id, value }) => {
r[id] = +r[id] > value ? r[id] : value;
return r;
}, []);
console.log(result);

How to transform this object using Object.keys and filtering

I have an object like:
const arr = {
[1]: [{id: 1, category: 1}, {id: 2, category: 2}],
[2]: [{id: 3, category: 2}, {id: 4, category: 2}],
[3]: [{id: 5, category: 3}, {id: 6, category: 3}]
}
Is it possible to move for example {id: 2, category: 2} to another place to have:
const arr = {
[1]: [{id: 1, category: 1}],
[2]: [{id: 2, category: 2}, {id: 3, category: 2}, {id: 4, category: 2}],
[3]: [{id: 5, category: 3}, {id: 6, category: 3}]
}
items with category = 2 should be in the array[2], 3 in 3 etc. It's possible to do that with Object.keys and filtering somehow? Or maybe there is a better solution?
You can use Object.keys() to iterate through arr, then using array#reduce you can group your array on the category value.
const arr = {[1]: [{id: 1, category: 1}, {id: 2, category: 2}], [2]: [{id: 3, category: 2}, {id: 4, category: 2}], [3]: [{id: 5, category: 3}, {id: 6, category: 3}]},
result = Object.keys(arr).reduce((r,k) => {
arr[k].forEach(({id, category}) => {
r[category] = r[category] || [];
r[category].push({id, category});
})
return r;
},{});
console.log(result);
You can use array#concat all the values of your object, then using array#reduce group object based on category.
const arr = {[1]: [{id: 1, category: 1}, {id: 2, category: 2}], [2]: [{id: 3, category: 2}, {id: 4, category: 2}], [3]: [{id: 5, category: 3}, {id: 6, category: 3}]},
result = [].concat(...Object.values(arr)).reduce((r,{id, category}) => {
r[category] = r[category] || [];
r[category].push({id, category});
return r;
},{});
console.log(result);
Yes, the Object.keys can be used to traverse the array. Then, using Array.splice and Array.push, you can remove item and push it to proper place. Please check the following code:
const arr = {
[1]: [{id: 1, category: 1}, {id: 2, category: 2}, {id: 7, category: 3}],
[2]: [{id: 3, category: 2}, {id: 4, category: 2}],
[3]: [{id: 5, category: 3}, {id: 6, category: 3}]
};
Object.keys(arr).forEach(function(k){
for(var j = 0; j < arr[k].length;j++) {
if(arr[k][j].category!=k) {
var removedItem = arr[k].splice(arr[k].indexOf(j), 1);
var pushedArr = arr[removedItem[0].category];
if(pushedArr) {
pushedArr.push(removedItem[0]);
j--;
}
}
}
});
console.log(arr);

Categories