Reputation: 1401
I have an array of objects like this below.
[
{
product_id: 4,
product_name: "Samsung",
category_name: "Tv and home appliance",
is_Available: 1
},
{
product_id: 8,
product_name: "Apple",
category_name: "Home gadgets",
is_Available: 1
},
{
product_id: 9,
product_name: "Verifone",
category_name: "Electronics",
is_Available: 0
}
]
I want to split this array into two based on is_Available flag value. So i did like this using reduce.
const formmattedResponse = data.reduce((arr,el) => {
if(el.is_Available === 1) {
arr.push({...el});
}
return arr;
},[]);
But, i need this type of formatted data like below based on above data array
{
availableData: [{
product_id: 4,
product_name: "Samsung",
category_name: "Tv and home appliance",
is_Available: 1
},
{
product_id: 8,
product_name: "Apple",
category_name: "Home gadgets",
is_Available: 1
}
],
notAvailableData: [{
product_id: 9,
product_name: "Verifone",
category_name: "Electronics",
is_Available: 0
}
]
}
Upvotes: 9
Views: 14998
Reputation: 2059
I've seen a lot of examples using Array.reduce()
, which has the advantage of doing all the computation in a single loop, but I've found a solution that in my opinion is easier to read, even if internally it requires two loops instead of one.
I started from a native implementation of the lodash method called difference()
, as you can find in the great You Might Not Need Lodash page.
const difference = (arr1, arr2) => arr1.filter(x => !arr2.includes(x))
Once I was able to create a new array from the values of the original array that are not in the filtered one, the implementation became very easy.
// filter the values that satisfy the condition
const firstResult = originalArray.filter(q => q.is_Available === 1);
// compute the rest by using the difference() method
const secondResult = difference(originalArray, firstResult);
At this point the whole logic can be extracted in a new partition()
method.
// import difference, or declare it before partition
const partition = (arr, condition) => {
const arr1 = arr.filter(condition);
const arr2 = difference(arr, arr1);
return [arr1, arr2];
};
And here is a full snippet on how to make it work with your data
const testableArray = [
{
product_id: 4,
product_name: 'Samsung',
category_name: 'Tv and home appliance',
is_Available: 1,
},
{
product_id: 8,
product_name: 'Apple',
category_name: 'Home gadgets',
is_Available: 1,
},
{
product_id: 9,
product_name: 'Verifone',
category_name: 'Electronics',
is_Available: 0,
},
];
const [arrayOne, arrayTwo] = partition(testableArray, q => q.is_Available === 1);
Upvotes: 0
Reputation: 386600
UPDATE 2024
With Object.groupBy
, it goes shorter by taking a group value.
const
data = [{ product_id: 4, product_name: "Samsung", category_name: "Tv and home appliance", is_Available: 1 }, { product_id: 8, product_name: "Apple", category_name: "Home gadgets", is_Available: 1 }, { product_id: 9, product_name: "Verifone", category_name: "Electronics", is_Available: 0 }],
result = Object.groupBy(data, ({ is_Available }) => is_Available
? 'availableData'
: 'notAvailableData'
);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
You could take an array and push the objects according their availability with a single loop.
const
data = [{ product_id: 4, product_name: "Samsung", category_name: "Tv and home appliance", is_Available: 1 }, { product_id: 8, product_name: "Apple", category_name: "Home gadgets", is_Available: 1 }, { product_id: 9, product_name: "Verifone", category_name: "Electronics", is_Available: 0 }],
result = data.reduce((r, o) => {
r[o.is_Available ? 'availableData' : 'notAvailableData'].push(o);
return r;
}, { availableData: [], notAvailableData: [] });
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Upvotes: 19
Reputation: 59
If not using lodash, may I suggest this :
var arr = [
{
product_id: 4,
is_Available: 1
},
{
product_id: 8,
is_Available: 1
},
{
product_id: 9,
is_Available: 0
}
]
const res = {notAvailableData: []}
res.availableData = arr.filter((a) => a.is_Available || !res.notAvailableData.push(a))
console.log(res)
.push()
returns the new length of the array, so ![].push shouldn't ever be true
Upvotes: 0
Reputation: 302
The lodash partition
function was designed to solve this problem:
import { partition } from "lodash";
const [availableData, notAvailableData] = partition(items, "is_Available");
const formattedResponse = { availableData, notAvailableData };
where items is the array of objects given in the question.
Upvotes: 3
Reputation: 3371
I believe that you can find partition functions in some libraries e.g. lodash that will split an array into two arrays, one that matches the condition and another that doesn't. I've written a quick version here to demo it.
const data = [{"product_id":4,"product_name":"Samsung","category_name":"Tv and home appliance","is_Available":1},{"product_id":8,"product_name":"Apple","category_name":"Home gadgets","is_Available":1},{"product_id":9,"product_name":"Verifone","category_name":"Electronics","is_Available":0}];
const partition = (array, filter_fn) =>
array.reduce(
(acc, val) => (acc[filter_fn(val) ? 0 : 1].push(val), acc),
[[], []]
);
const new_keys = ['availableData', 'notAvailableData'];
const result = Object.fromEntries(
partition(data, (item) => item.is_Available)
.map((arr, i) => [new_keys[i], arr])
);
console.log(result);
Upvotes: 1
Reputation: 1426
You have two options: you either filter the list twice or you can add a different accumulator for your reduce function which holds two arrays.
This advantage of the reduce is that only iterate your array once, making it more efficient than the double filter.
I pass a object with 2 properties: availableData and notAvailableData as the initial value for the reduce. During the reduce, I check the property that you want to filter on and add it to the right list. In the reduce function, I return the context object so the next iteration has it also.
The reduce returns that object in the end, completing the sort.
var arr = [
{
product_id: 4,
product_name: "Samsung",
category_name: "Tv and home appliance",
is_Available: 1
},
{
product_id: 8,
product_name: "Apple",
category_name: "Home gadgets",
is_Available: 1
},
{
product_id: 9,
product_name: "Verifone",
category_name: "Electronics",
is_Available: 0
}
]
var context = arr.reduce((ctx, el) => {
if (el.is_Available) {
ctx.availableData.push(el);
} else {
ctx.notAvailableData.push(el);
}
return ctx
}, {availableData: [], notAvailableData: []})
console.log(context);
Upvotes: 1
Reputation: 814
modified Snippet could be like
const formmattedResponse = data.reduce((arr,el) => {
let finalResp = {
availableData: [],
notAvailableData : []
}
if(el.is_Available === 1) {
finalResp["availableData"].push({...el});
} else {
finalResp["notAvailableData "].push({...el});
}
return finalResp;
},[]);
Upvotes: 0
Reputation: 2665
const data = [
{
product_id: 4,
product_name: "Samsung",
category_name: "Tv and home appliance",
is_Available: 1
},
{
product_id: 8,
product_name: "Apple",
category_name: "Home gadgets",
is_Available: 1
},
{
product_id: 9,
product_name: "Verifone",
category_name: "Electronics",
is_Available: 0
}
];
const result = {
availableData: data.filter(el => el.is_Available),
notAvailableData: data.filter(el => !el.is_Available),
};
console.log(result);
You can use Array.filter() to filter your array based on is_Available.
Upvotes: 2