I have the reducer that contains some of the list objects.
const list = [
{
name: 'A',
products: { items: [] },
},
{
name: 'B',
products: { items: [{ qty: 1 }] },
},
]
I want to add new items to the product key.
reducer
export const addProductToSubscription = (state, { name, products }) => ({
...state,
list: state.list.map((v) =>
name === v.subscriptionName ? [...v.products, { ...v.products, items: products }] : v
),
})
disptach like this,
dispatch("A",[{qty:2}])
expected output
const list = [
{
name: 'A',
products: { items: [{ qty: 2 }] },
},
{
name: 'B',
products: { items: [{ qty: 1 }] },
},
]
What reducer not updating the state.
Thanks!!
I've recreated your environment and end up like-
const state = {
list: [
{
name: "A",
products: { items: [] },
},
{
name: "B",
products: { items: [{ qty: 1 }] },
},
],
};
const updateState = (state, { name, products }) => {
return {
...state,
list: state.list.map(v => {
return {
...v,
products: {
...v.products,
items: [
...v.products.items,
...products
]
}
}
}),
};
};
const res = updateState(state, { name: "A", products: [{ qty: 2 }, {qty: 4}] });
console.log(JSON.stringify(res));
.as-console-wrapper{min-height: 100%!important; top: 0}
A more advanced solution than Object.assign and spread operator(...) - immutability-helper
const update = require('immutability-helper');
const assert = require('assert');
const list = [
{
name: 'A',
products: { items: [] },
},
{
name: 'B',
products: { items: [{ qty: 1 }] },
},
];
function addProductToSubscription(state = list, { name, products }) {
return update(state, {
$apply: (self) => {
return self.map((v) => {
if (v.name === name) {
return update(v, { products: { items: { $push: products } } });
}
return v;
});
},
});
}
const actual = addProductToSubscription(undefined, { name: 'A', products: [{ qty: 2 }] });
console.log(JSON.stringify(actual, null, 2));
assert(actual !== list, 'new copy');
assert(actual[0] !== list[0], 'new copy for A object');
assert(actual[0].products !== list[0].products, 'new copy for A object products');
assert(actual[0].products.items !== list[0].products.items, 'new copy for A object products items');
Output:
[
{
"name": "A",
"products": {
"items": [
{
"qty": 2
}
]
}
},
{
"name": "B",
"products": {
"items": [
{
"qty": 1
}
]
}
}
]
Take the new copy using spread operator and update to the state
export const addProductToSubscription = (state, { name, products }) => ({
...state,
list: state.list.map((v) =>
v.name === name
? {
...v,
products: { items: [...v.products.items, ...products] },
}
: v
),
});
Related
I have an array of ids ['id1', 'id3'].
I also have an array of items:
[
{
children: [{
children: [{
id: "id1", //This is value I need to find
status: { state: false}, //this is value I need to change
}],
}],
},
{
children: [{
children: [{
id: "id2",
status: { state: false},
}],
}],
},
{
children: [{
children: [{
id: "id3",
status: { state: false},
}],
}],
},
]
My goal is to find every item by id from first array, and change attribute state, then return all items having included those I have changed.
This was my try, but it returns all items again, also Im not sure how to change the attribute.
items.filter(item =>
item.children.map(child =>
child.children.map(object =>
idsArray.map(id => id === object.id)
)))
I think you can use recursive function something like below :
let ids = ["id1", "id2"];
let arrayOfItems = [
{
children: [
{
children: [
{
id: "id1",
status: {
state: false
}
}
]
}
]
},
{
children: [
{
children: [
{
id: "id2",
status: {
state: false
}
}
]
}
]
},
{
children: [
{
children: [
{
id: "id3",
status: {
state: false
}
}
]
}
]
}
];
function changeStatus(arrayOfItems, ids) {
return arrayOfItems.map((e) => {
if (e.id && ids.includes(e.id)) {
return { ...e, status: { state: true } };
} else if (e.children) {
return { ...e, children: changeStatus(e.children, ids) };
} else {
return { ...e };
}
});
}
console.log(changeStatus(arrayOfItems,ids));
I am trying to remove all the _er and _bx from the array, how can I do it? The way I tried doesn't seem to work. I'd like to see a solution where it removes all after _, and aswell only the letter that I put in for e.g remove all _ with er after.
const nullValue = {
collection: [{
name: "test_er"
},
{
name: "test_bx"
},
{
name: "fred"
},
{
name: "test_er"
}
]
};
const newArr = []
for (let [key, item] of nullValue.collection.entries()) {
item.name.replace(/_er/g, '')
newArr.push(item)
}
console.log(newArr)
Is this what you're looking for?
const nullValue = {
collection: [
{
name: 'test_er',
},
{
name: 'test_bx',
},
{
name: 'fred',
},
{
name: 'test_er',
},
],
};
nullValue.collection = [
...nullValue.collection.map(item => ({
name: item.name.replace(/_.*$/, ''),
})),
];
console.log(nullValue);
You can also use .split('_')[0] with the map method similar to Dmitry's answer... This gives you the first string of the split array, split at the underscore...
const nullValue = {
collection: [{
name: "test_er"
},
{
name: "test_bx"
},
{
name: "fred"
},
{
name: "test_er"
}
]
};
nullValue.collection = [ ...nullValue.collection.map( names => ({ name: names.name.split('_')[0], })),]
console.log(nullValue)
If you want to keep the original array of objects...
const nullValue = {
collection: [{
name: "test_er"
},
{
name: "test_bx"
},
{
name: "fred"
},
{
name: "test_er"
}
]
};
const newArr = { collection :
[ ...nullValue.collection.map( names =>
({ name: names.name.split('_')[0], })),
]}
console.log('newArr = ', newArr)
console.log('nullValue = ', nullValue)
You were VERY close with your original code, but the mistake was that String.replace() does not operate in-place, but rather returns its result. I've modified your code and added a comment below:
const nullValue = {
collection: [{
name: "test_er"
},
{
name: "test_bx"
},
{
name: "fred"
},
{
name: "test_er"
}
]
};
const newArr = []
for (let [key, item] of nullValue.collection.entries()) {
// My change is here
newArr.push( item.name.replace(/_er/g, '') )
}
console.log(newArr)
const nullValue = {
collection: [
{
name: "test_er"
},
{
name: "test_bx"
},
{
name: "fred"
},
{
name: "test_er"
}
]
};
nullValue.collection = nullValue.collection.map(i => i.name.replace(/_.*$/, ''))
console.log(nullValue)
This is preferable to .map() since you don't need a new array. You just want to change the strings:
const nullValue = {
collection: [
{ name: "test_er" },
{ name: "test_bx" },
{ name: "fred" },
{ name: "test_er" }
]
};
nullValue.collection.forEach(i => i.name = i.name.replace(/_.*$/, ''));
console.log(nullValue.collection);
I'm wondering, I have the following data structure:
data = [
{
name: 'Alpha',
},
{
name: 'Alfa',
},
{
name: 'Bravo',
},
{
name: 'Brafo',
},
{
name: 'Charlie',
},
{
name: 'Charly',
},
...
{
name: 'Zulu',
},
{
name: 'Zulo',
},
]
I'm expecting there to be at least one, usually more, key for each letter of the alphabet. However, if there isn't a single data.name I would still like in the below data structure to have an empty domains array [].
I was wondering, how could this be manipulated into the following data structure:
data = {
a: {
domains: [
{
name: 'Alpha',
},
{
name: 'Alfa',
},
],
},
b: {
domains: [
...
]
},
...
z: {
domains: [
...
]
},
};
I have used a few methods, which involved a pre-constructed "alphbetised" key = object array, then filtered each on the first letter of the data.name value...but I was wondering if there was a standard and performant method to acheive this?
Using reduce()
const data = [{name:"Alpha"},{name:"Alfa"},{name:"Bravo"},{name:"Brafo"},{name:"Charlie"},{name:"Charly"},{name:"Zulu"},{name:"Zulo"}]
const res = data.reduce((a, v) => {
// prepare key
let key = v.name.substring(0,1).toLowerCase()
// check key in accumulator
if (!a[key]) {
// assign domain object
a[key] = {domains: []}
}
// push domain array
a[key].domains.push(v)
return a
}, {})
console.log(res)
Here is what you want:
data = [
{
name: 'Alpha',
},
{
name: 'Alfa',
},
{
name: 'Bravo',
},
{
name: 'Brafo',
},
{
name: 'Charlie',
},
{
name: 'Charly',
},
{
name: 'Zulu',
},
{
name: 'Zulo',
},
];
console.log(data.reduce((a, c) => {
const firstLetter = c.name[0].toLowerCase();
if (a[firstLetter]) {
a[firstLetter].domains.push(c);
} else {
a[firstLetter] = { domains: [c] };
}
return a;
}, {}));
I have the following:
const itemsArr = [{
id: 0,
baseDetails: {
modelNames: ["Atoga3"],
companies: ['Sunafga']
}
},
{
id: 1,
baseDetails: {
modelNames: ["Bisuda-X23", "Oidas"],
companies: ["Sunafga", "Kemaite"]
}
},
{
id: 2,
baseDetails: {
modelNames: ["Zarusa-M3", "Kalasi-W"],
companies: ["Abado", "Sunafga"]
}
}
]
What I want to achieve is to have an array with each company -> modelName combination.
So it should look like :
[{
value: 'sunafga',
label: 'Sunafga',
children: [{
value: 'atoga3',
label: 'Atoga3'
},
{
value: 'bisuda-x23',
label: 'bisuda-X23'
},
{
value: 'oidas',
label: 'Oidas'
},
{
value: 'zarusa-m3',
label: 'Zarusa-M3'
},
{
value: 'valasi-W',
label: 'Kalasi-W'
}
]
},
{
value: 'kemaite',
label: 'Kemaite',
children: [{
value: 'bisuda-x23',
label: 'bisuda-X23'
},
{
value: 'oidas',
label: 'Oidas'
},
]
},
]
you probably want a two step transform here, one to a useful structure to remove all those dups, then just nudge that into your desired structure
const itemsArr = [{
id: 0,
baseDetails: {
modelNames: ["Atoga3"],
companies: ['Sunafga']
}
},
{
id: 1,
baseDetails: {
modelNames: ["Bisuda-X23", "Oidas"],
companies: ["Sunafga", "Kemaite"]
}
},
{
id: 2,
baseDetails: {
modelNames: ["Zarusa-M3", "Kalasi-W"],
companies: ["Abado", "Sunafga"]
}
}
]
// transform to a useful structure for removing duplicates
const companyMap = itemsArr.reduce((acc, val) => {
val.baseDetails.companies.forEach(c => {
acc[c] = val.baseDetails.modelNames.reduce((a, m) => Object.assign(a, {[m]: true}), (acc[c] || {}))
});
return acc
}, {})
// transform your useful structure to the desired one
const newArray = Object.entries(companyMap).map(([company, models]) => {
return {
value: company.toLowerCase(),
label: company,
children: Object.keys(models).map(model => ({label: model, value: model.toLowerCase()}))
}
})
console.log(newArray)
you could use this if you want as your intermediary transform if you want to reduce all the way down:
const companyMap = itemsArr.reduce((cMap, item) =>
Object.assign(cMap,
item.baseDetails.companies.reduce((iMap, c) =>
Object.assign(iMap,
{[c]: item.baseDetails.modelNames.reduce((a, m) => Object.assign(a, {[m]: true}), (cMap[c] || {}))}
)
, {})
)
, {})
Here's a solution if using reduce isn't mandatory:
const itemsArr = [{
id: 0,
baseDetails: {
modelNames: ["Atoga3"],
companies: ['Sunafga']
}
},
{
id: 1,
baseDetails: {
modelNames: ["Bisuda-X23", "Oidas"],
companies: ["Sunafga", "Kemaite"]
}
},
{
id: 2,
baseDetails: {
modelNames: ["Zarusa-M3", "Kalasi-W"],
companies: ["Abado", "Sunafga"]
}
}
];
const result = [];
itemsArr.forEach(item => {
item.baseDetails.companies.forEach(company => {
let companyEntry = result.find(resultEntry => resultEntry.label === company);
if (!companyEntry) {
companyEntry = {
label: company,
value: company.toLowerCase(),
children: []
};
result.push(companyEntry);
}
const companyChildren = companyEntry.children;
item.baseDetails.modelNames.forEach(modelName => {
if (!companyChildren.find(companyModel => companyModel.label === modelName)) {
companyChildren.push({
label: modelName,
value: modelName.toLowerCase()
});
}
});
});
});
console.log(result);
Currently I have two different array of objects and my end result is I am trying to have one single array of objects.
const postIds = [
{ id: 4938960132 },
{ id: 5586491011 },
{ id: 4671908225 },
{ id: 4594788047 },
{ id: 4657970305 }
]
const images = [
{ featuredImage: 'https://www.rusticfurnitureboston.com/hubfs/Blog_Media/rustic20coffee20table.jpeg%3Ft=1528912781831-6.jpeg' },
{ featuredImage: 'https://www.rusticfurnitureboston.com/hubfs/Blog_Media/Amazing-Table-For-Flamboyant-Furniture-Home-Design-Ideas-With-Rustic-Furniture-Coffee-Table.jpg%3Ft=1528912781831-6.jpeg' },
{ featuredImage: 'https://www.rusticfurnitureboston.com/hubfs/Blog_Media/envoy-lookout-rooftop-11b-780x520.jpg%3Ft=1528912781831-6.jpeg' },
{ featuredImage: 'https://www.rusticfurnitureboston.com/hubfs/Blog_Media/Alexanderplatz_03.jpg%3Ft=1528912781831-6.jpeg' },
{ featuredImage: 'https://www.rusticfurnitureboston.com/hubfs/Blog_Media/mountain-landscape-wallpaper-29048-29765-hd-wallpapers.jpg%3Ft=1528912781831-6.jpeg' }
]
What I am hoping to have at the end is a data structure like the following
const newData = [
{ id: 4938960132, featuredImage: 'https://www.rusticfurnitureboston.com/hubfs/Blog_Media/rustic20coffee20table.jpeg%3Ft=1528912781831-6.jpeg' },
{ id: 5586491011, featuredImage: 'https://www.rusticfurnitureboston.com/hubfs/Blog_Media/Amazing-Table-For-Flamboyant-Furniture-Home-Design-Ideas-With-Rustic-Furniture-Coffee-Table.jpg%3Ft=1528912781831-6.jpeg' },
{ id: 4671908225, featuredImage: 'https://www.rusticfurnitureboston.com/hubfs/Blog_Media/envoy-lookout-rooftop-11b-780x520.jpg%3Ft=1528912781831-6.jpeg' },
{ id: 4594788047, featuredImage: 'https://www.rusticfurnitureboston.com/hubfs/Blog_Media/mountain-landscape-wallpaper-29048-29765-hd-wallpapers.jpg%3Ft=1528912781831-6.jpeg'},
{ id: 4657970305, featuredImage: 'https://www.rusticfurnitureboston.com/hubfs/Blog_Media/mountain-landscape-wallpaper-29048-29765-hd-wallpapers.jpg%3Ft=1528912781831-6.jpeg' }
]
I've been trying a lot of different things here such as reduce, spread operator and other es6 functions but cannot seem to get the data structure that I am looking for.
Any help would be much appreciated
Assuming the two arrays have the same length:
const newData = [...postIds.map((postId, i) => Object.assign({}, postId, images[i]))];
Alternativelly, with ... operator:
const newData = [...postIds.map((item, i) => {
return {
...item,
...images[i]
};
})];
Working snippet:
const postIds = [
{ id: 4938960132 },
{ id: 5586491011 },
{ id: 4671908225 },
{ id: 4594788047 },
{ id: 4657970305 }
]
const images = [
{ featuredImage: 'https://www.rusticfurnitureboston.com/hubfs/Blog_Media/rustic20coffee20table.jpeg%3Ft=1528912781831-6.jpeg' },
{ featuredImage: 'https://www.rusticfurnitureboston.com/hubfs/Blog_Media/Amazing-Table-For-Flamboyant-Furniture-Home-Design-Ideas-With-Rustic-Furniture-Coffee-Table.jpg%3Ft=1528912781831-6.jpeg' },
{ featuredImage: 'https://www.rusticfurnitureboston.com/hubfs/Blog_Media/envoy-lookout-rooftop-11b-780x520.jpg%3Ft=1528912781831-6.jpeg' },
{ featuredImage: 'https://www.rusticfurnitureboston.com/hubfs/Blog_Media/Alexanderplatz_03.jpg%3Ft=1528912781831-6.jpeg' },
{ featuredImage: 'https://www.rusticfurnitureboston.com/hubfs/Blog_Media/mountain-landscape-wallpaper-29048-29765-hd-wallpapers.jpg%3Ft=1528912781831-6.jpeg' }
]
const newData = [...postIds.map((item, i) => Object.assign({}, item, images[i]))];
console.log(newData)
You creduce both array by mapping the objects at the same index and by assigning to a new object.
This works for an arbitrary count of arrays.
const
postIds = [{ id: 4938960132 }, { id: 5586491011 }, { id: 4671908225 }, { id: 4594788047 }, { id: 4657970305 }],
images = [{ featuredImage: 'https://www.rusticfurnitureboston.com/hubfs/Blog_Media/rustic20coffee20table.jpeg%3Ft=1528912781831-6.jpeg' }, { featuredImage: 'https://www.rusticfurnitureboston.com/hubfs/Blog_Media/Amazing-Table-For-Flamboyant-Furniture-Home-Design-Ideas-With-Rustic-Furniture-Coffee-Table.jpg%3Ft=1528912781831-6.jpeg' }, { featuredImage: 'https://www.rusticfurnitureboston.com/hubfs/Blog_Media/envoy-lookout-rooftop-11b-780x520.jpg%3Ft=1528912781831-6.jpeg' }, { featuredImage: 'https://www.rusticfurnitureboston.com/hubfs/Blog_Media/Alexanderplatz_03.jpg%3Ft=1528912781831-6.jpeg' }, { featuredImage: 'https://www.rusticfurnitureboston.com/hubfs/Blog_Media/mountain-landscape-wallpaper-29048-29765-hd-wallpapers.jpg%3Ft=1528912781831-6.jpeg' }],
result = [images, postIds].reduce(
(r, a) => a.map((o, i) => Object.assign({}, o, r[i])),
[]
);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }