Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 1 year ago.
Improve this question
I have 2 object in array
dataV[1] = {
"resolution": "4"
};
datas[1] = {
{qty_approved: "1", resolution: "5", status: "", order: "1332"}
}
if both index same then i want to update with the value from 1st. I want to update resolution value to 4 from 5. Based on upcoming value from new array value in dataV
Expected output like this :
datas[1] = {
{qty_auth: "1", resolution: "4", status: "", order: "1332"}
}
Wherever you're updating the value of dataV you can do something like this, to update the datas:
datas = datas.map((data, i) => {
return { ...data, resolution: dataV[i].resolution };
});
And if you're using react you can do the same thing in useEffect with dataV as a dependency. So, whenever dataV changes, datas will change automatically.
let array1 = [
{
resolution: '4',
},
];
let array2 = [
{ qty_approved: '1', resolution: '5', status: '', order: '1332' },
];
let array3 = array1.map((element, index) => {
if (typeof array2[index] != 'undefined') {
return { ...array2[index], ...element};
}
return element;
});
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax
Since you can get the corresponding element by array index, you can get the corresponding resolution as easy as the following snippet:
datas.forEach( (_, i) => {
datas[i].resolution = dataV[i].resolution
})
Using Array#reduce, iterate over dataV while updating a Map where the index is the key and the resolution is the value
Using Array#forEach, iterate over datas, if the above map has a key of such index, update the resolution
const
dataV = [ { "resolution": "4" }, { "resolution": "7" }, { "resolution": "1" } ],
datas = [
{ qty_approved: "1", resolution: "5", status: "", order: "1332" },
{ qty_approved: "1", resolution: "3", status: "", order: "1331" },
{ qty_approved: "1", resolution: "9", status: "", order: "1333" },
];
const indexResolutionMap = dataV.reduce((map, { resolution }, i) =>
map.set(i, resolution)
, new Map);
datas.forEach((e, i) => {
const resolution = indexResolutionMap.get(i);
if(resolution) e.resolution = resolution;
});
console.log(datas);
The following approach is going to map each item of datas. The mapping function nevertheless will be a real function (not an arrow function), thus it is aware of map's second thisArg argument which for the OP's use case will be the dataV array where one wants to read the resolution values from.
The advantage of such an approach is, that one can work with a reusable mapper function which is agnostic to outside array references because it does process an array while the related/corresponding array gets provided as the mapper functions this context.
The mapping functionality itself does try to not mutate the original item reference by loosely decoupling the reference via creating a shallow copy of the entire item. On top the resolution value which was read from the corresponding array via this[idx].resolution gets assigned to the just created shallow copy.
const datas = [
{ qty_approved: "1", resolution: "5", status: "", order: "1332" },
{ qty_approved: "1", resolution: "3", status: "", order: "1331" },
{ qty_approved: "1", resolution: "9", status: "", order: "1333" },
];
const dataV = [{
"resolution": "4",
}, {
"resolution": "7",
}, {
"resolution": "1",
}];
// mapping approach.
function copyItemAndAssignSameIndexResolutionFromTargetArray(item, idx) {
// - this merge pattern is agnostic about an `item`'s structure.
// - `item` could feature more keys but just `resolution` gets reassigned.
return Object.assign({}, item, { resolution: this[idx].resolution });
}
console.log(
'mapped version of changed `dataV` items ...',
datas.map(copyItemAndAssignSameIndexResolutionFromTargetArray, dataV)
);
console.log('still unmutated `datas` ...', { datas });
.as-console-wrapper { min-height: 100%!important; top: 0; }
In case the OP wants to mutate each of the datas array's items, the above introduced mapper function changes slightly in order to be utilized by a context aware forEach ...
const datas = [
{ qty_approved: "1", resolution: "5", status: "", order: "1332" },
{ qty_approved: "1", resolution: "3", status: "", order: "1331" },
{ qty_approved: "1", resolution: "9", status: "", order: "1333" },
];
const dataV = [{
"resolution": "4",
}, {
"resolution": "7",
}, {
"resolution": "1",
}];
// mapping approach.
function assignSameIndexResolutionFromTargetArray(item, idx) {
item.resolution = this[idx].resolution;
// Object.assign(item, { resolution: this[idx].resolution });
}
datas.forEach(assignSameIndexResolutionFromTargetArray, dataV);
console.log('mutated `datas` array ...', { datas });
.as-console-wrapper { min-height: 100%!important; top: 0; }
Or (desperately guessing) is the OP looking for a solution where a datas item has to be updated/mutated by an explicitly provided dataV item? Something like this?..
const datas = [
{ qty_approved: "1", resolution: "3", status: "", order: "1331" },
{ qty_approved: "1", resolution: "5", status: "", order: "1332" },
{ qty_approved: "1", resolution: "9", status: "", order: "1333" },
];
const dataV = [{
"resolution": "1",
}, {
"resolution": "4",
}, {
"resolution": "7",
}, ];
function updateResolution(targetArray, sourceArray, resolutionItem) {
const updateIndex =
sourceArray.findIndex(item =>
item.resolution === resolutionItem.resolution
);
targetArray[updateIndex].resolution = resolutionItem.resolution;
return targetArray[updateIndex];
}
console.log(
'updateResolution(datas, dataV, { resolution: "4"}) ...',
updateResolution(datas, dataV, { resolution: "4"})
);
console.log('mutated `datas` array ...', { datas });
console.log(
'updateResolution(datas, dataV, { resolution: "7"}) ...',
updateResolution(datas, dataV, { resolution: "7"})
);
console.log('mutated `datas` array ...', { datas });
.as-console-wrapper { min-height: 100%!important; top: 0; }
Related
I have a data like this in array.
[
{
"teamName": "TeamA",
"players": ["1","2"]
},
{
"teamName": "TeamB",
"players": ["2"]
}
]
and I want to replace players id which match in other array
players = [
{
"id": "1",
"playername": "alex"
},
{
"id": "2",
"playername": "john"
}
]
So output will be like this
[
{
"teamName": "TeamA",
"players": [
{
"id": "1",
"playername": "alex"
},
{
"id": "2",
"playername": "john"
}]
},
{
"teamName": "TeamB",
"players": [
{
"id": "2",
"playername": "john"
}]
}
]
I tried to find by for loop and where it will find and replace but that's not working for me.
you can do this by iterating over first array and updating the players property of each element in that array.
let arrOne = [
{
"teamName": "TeamA",
"players": ["1","2"]
},
{
"teamName": "TeamB",
"players": ["2"]
}
]
players = [
{
"id": "1",
"playername": "alex"
},
{
"id": "2",
"playername": "john"
}
]
// solution
arrOne.forEach( teamObject => {
let newPlayerArray = [];
teamObject.players.forEach( id => {
let newPlayerObject = {};
newPlayerObject.id = id;
newPlayerObject.playername = players.find( player => player.id == id)?.playername;
newPlayerArray.push(newPlayerObject)
})
teamObject.players = newPlayerArray;
})
One approach:
// defining the variables, naming 'teams' as it was unnamed in
// the original post:
let teams = [
{
"teamName": "TeamA",
"players": ["1", "2"]
},
{
"teamName": "TeamB",
"players": ["2"]
}
],
// updated the name of this Array of Objects due to the naming
// clash between the original name ('players') when using
// destructuring assignments while iterating the 'teams' Array,
// because of an identically-named property:
playerDetails = [{
"id": "1",
// I updated this property-name to use camelCase consistently:
"playerName": "alex"
},
{
"id": "2",
"playerName": "john"
}
],
// rather than editing the original Array, we create a new one
// by iterating over the teams Array, using Array.prototype.map():
combined = teams.map(
// using destructuring assignement to retrieve the named properties
// of the Object passed in to the function:
({
teamName,
players
}) => {
// because we're returning an Object literal, we have to use return and wrap
// the anonymous callback function of the Arrow function in curly braces ('{...}')
// to avoid the returned Object-literal being misinterpreted as a function body:
return {
// we return the teamName property unchanged:
teamName,
// but here we update the players property, we iterate over the players Array,
// again using players.prototype.map() to update the existing Array based on the
// result of actions taken in the anonymous Arrow function:
players: players.map(
// we pass in a reference to the 'id' enclosed within the player Array,
// giving it a verbose/clear name given that 'id' would be a sensible/short
// name, but is used within the enclosed function as the named property of
// the other function we're working with.
// within the anonymous function we use Array.prototype.find():
(teams_playerID) => playerDetails.find(({
// passing in a reference to the 'id' property-name of the Object
// within the playerDetails Array:
id
// and here we check to see if the 'id' of the playerDetails Array is
// exactly-equal to the teams_playerID variable; if so this Object is
// returned and the 'players' Array is updated, and changed from a String
// to the found Object; if no match is found the current 'players' Array-value
// is unchanged:
}) => id == teams_playerID ))
}
});
console.log(combined);
// [{"teamName":"TeamA","players":[{"id":"1","playerName":"alex"},{"id":"2","playerName":"john"}]},{"teamName":"TeamB","players":[{"id":"2","playerName":"john"}]}]
JS Fiddle demo.
References:
Array.prototype.find().
Array.prototype.map().
Arrow functions.
Destructuring assignemnt.
You can build the result by stepping through the list of teams, looking up each player by their id, and adding the player record to the result’s players array.
const teams = [
{
"teamName": "TeamA",
"players": ["1", "2"]
},
{
"teamName": "TeamB",
"players": ["2"]
}
]
const players = [
{
"id": "1",
"playername": "alex"
},
{
"id": "2",
"playername": "john"
}
]
let result = []
teams.forEach(team => {
let record = {
"teamname": team.teamName,
"players": []
}
team.players.forEach(player_id => {
record.players.push(players.find(p => p.id === player_id))
})
result.push(record)
})
console.log(JSON.stringify(result, null, 4))
I am preparing an array like this
datas[5] = { "qty_sized": "1", "resolution": "5", "status": "", "order": 1342 };
where [5] is dynamic from response.
I have and object mydata and inside that I have a object items.
I push array to object items, with assign
Object.assign(mydatadata.items, datas);
Now mydata.items has an array set,
`
items{
1 {qty_auth: "", resolution: "4", status: "", order: "1495"},
5 {qty_sized: "1", resolution: "4", status: "", order: "1485"}
}`
Now if qty_auth: "" , from which i need to check if qty_ is empty then remove the array . So expected output is something like this:
Note: qty_ is dynamic here.
items{ 5 {qty_sized: "1", resolution: "4", status: "", order: "1485"} }
and i want to result inside same object mydata.items
I tried something like this
const mydatadata.items = mydata.items.filter((o) =>
Object.keys(o).some((k) => k.startsWith("qty") && o[k])
);
console.log(result);
but its now giving me any output
Using Object#entries, get the key-value pairs of items
Using Array#filter, iterate over the above array
In each iteration, check if the current item has a key starting with qty_ whose value is not empty. You can do this using Object#keys, Array#some, and String#startsWith.
Using Object#fromEntries, convert the filtered pairs to an object again.
const obj = {
items: {
1: {qty_auth: "", resolution: "4", status: "", order: "1495"},
5: {qty_sized: "1", resolution: "4", status: "", order: "1485"}
}
};
obj.items = Object.fromEntries(
Object.entries(obj.items)
.filter(([_, item]) =>
Object.keys(item).some(key => key.startsWith('qty_') && item[key])
)
);
console.log(obj);
You're talking about an array, but using curly brackets instead of square brackets. For filter() to work it would have to look like:
mydata = {
items: [
{qty_auth: "", resolution: "4", status: "", order: "1495"},
{qty_sized: "1", resolution: "4", status: "", order: "1485"}
]
}
Assuming it is an actual array there's still a problem with "const mydatadata.items", or at least it throws an error for me because mydatadata is not initialized. Unless it's a typo and it should be mydata, but then you'd be redeclaring it. So depending on what you want:
mydata.items = mydata.items.filter((o) =>
Object.keys(o).some((k) => k.startsWith("qty") && o[k])
);
or
let mydatadata = {};
mydatadata.items = mydata.items.filter((o) =>
Object.keys(o).some((k) => k.startsWith("qty") && o[k])
);
Furthermore you're storing the result in mydatadata but you're logging the variable result.
So depending on the previous answer:
console.log(mydatadata);
or
console.log(mydata);
Here's a fiddle: https://jsfiddle.net/b57qa82d/
You should probably just be using an array rather than an object. It's not really clear from your question what structure you need as you keep changing the terminology to describe your data. For example: "Now mydata.items has an array set" but your code says that it should be object with keys, not an array.
So I suggest: get your data in an array, and filter it by iterating over each object's entries and checking to see if any of the keys starting with "qty" has a value that isn't an empty string. You can then assign that filtered array to myObject.items.
const data = [
{ "qty_sized": "0", "resolution": "5", "status": "", "order": 2 },
{ "qty_auth": "", "resolution": "5", "status": "", "order": 3 },
{ "qty_auth": "1", "resolution": "5", "status": "", "order": 1342 },
{ "qty_sized": "", "resolution": "2", "status": "", "order": 1 },
{ "qty_sized": "1", "resolution": "1", "status": "", "order": 142 }];
const filtered = data.filter(obj => {
return Object.entries(obj).find(([key, value]) => {
return key.startsWith('qty') && value;
});
});
const myObject = { items: filtered };
console.log(myObject);
Additional documentation
Object.entries
find
I am fetching a data from Laravel API this way
$inventory = Gifts::with('allocation')->get();
$response = [
'data' => $inventory->toArray(),
]
The output for the above looks like the image below in the console
This is what is inside the 0: {…}
{
"id": 1,
"name": "Bar 1",
"allocation": [
{
"id": 1,
"location_id": "1",
"qty": "2",
},
{
"id": 2,
"location_id": "4",
"qty": "32",
},
{
"id": 3,
"location_id": "7",
"qty": "12",
}
]
}
I'm trying to get an output like this
{
"isEditable": false,
"id": 1,
"name": "Bar 1",
"location1": "2"
"location4": "32"
"location7": "12"
}
It's an array that consists of 100+ entries like this and the allocation can be more or less or maybe empty as well
What I have done so far
const array = result.data(gift => ({ isEditable: false, ...gift }));
This adds "isEditable" field to the array.
You could use Array.prototype.map() to map the result array into a new one that only includes id, name, and the locationNN properties.
In the Array.prototype.map()'s callback:
Use the spread operator to separate the allocation property from the other properties of each array item (call it otherProps e.g.):
Spread the otherProps into a new object, inserting the isEditable property.
Map the allocation items into a key-value pair array, where the key is location_id appended to "location"; and the value is the qty property.
Use Object.fromEntries() on the key-value pair array to create an object, and spread that object into the outer object to be returned.
const output = result.map(r => {
const { allocation, ...otherProps } = r 1️⃣
return {
...otherProps, 2️⃣
isEditable: false,
...Object.fromEntries( 4️⃣
allocation.map(a => [`location${a.location_id}`, a.qty]) 3️⃣
)
}
})
demo
This solution uses reduce
const { allocation, ...rest } = gift
const processed = allocation.reduce((acc, loc, idx) => {
acc[`location${loc.location_id}`] = loc.qty
return acc
}, {})
const result = { ...rest, ...processed }
console.log(result)
I have the following data :
const data=
{
"1": [
{
"sales_project_id": 5,
"sales_project_name": "name",
"sales_project_est_rev": "123.00",
"project_status": {
"id": 1,
"label": "Start",
"description": null
}
},
{
"sales_project_id": 6,
"sales_project_name": "name2",
"sales_project_est_rev": "123.00",
"project_status": {
"id": 1,
"label": "Start",
"description": null
}
}
],
"2": [],
"4": []
}
These data are grouped in my backend based on their Status , in this case im only showing 2 status , but they are dynamic and can be anything the user defines.
What i wish to do is to transform the above data into the format below :
const data =
{
columns: [
{
id: // id of status here,
title: //label of status here,
cards: [
{
id : //sales_project_id here,
title: //sales_project_name here,
},
]
},
{
id: // id of status here,
title: //label of status here,
cards: [
{
id : //sales_project_id here,
title: //sales_project_name here,
},
]
}
]}
My guess would be to iterate over the data , however i am pretty unfamiliar with doing so , would appreciate someone's help!
Here is what i could come up with so far:
const array = []
Object.keys(a).map(function(keyName, keyIndex) {
a[keyName].forEach(element => {
#creating an object of the columns array here
});
})
after some trial and error , manage to accomplish this , however , im not sure if this is a good method to do so.
Object.keys(projects).map(function(keyName, keyIndex) {
// use keyName to get current key's name
// and a[keyName] to get its value
var project_object = {}
project_object['id'] = projects[keyName][0].id
project_object['title'] = projects[keyName][0].label
project_object['description'] = projects[keyName][0].description
console.log( projects[keyName][1])
var card_array = []
projects[keyName][1].forEach(element => {
var card = {}
card["id"] = element.sales_project_id
card["title"] = element.sales_project_name
card["description"] = element.sales_project_est_rev
card_array.push(card)
});
project_object["cards"] = card_array
array.push(project_object)
})
Im basically manipulating some the scope of the variables inorder to achieve this
See my solution, I use Object.keys like you, then I use reduce:
const newData = { columns: Object.keys(data).map((item) => {
return data[item].reduce((acc,rec) => {
if (typeof acc.id === 'undefined'){
acc = { id: rec.project_status.id, title: rec.project_status.label, ...acc }
}
return {...acc, cards: [...acc.cards, { id:rec.sales_project_id, title:rec.sales_project_name}]}
}, {cards:[]})
})}
See full example in playground: https://jscomplete.com/playground/s510194
I'd just do this. Get the values of data using Object.values(data) and then use reduce to accumulate the desired result
const data=
{
"1": [
{
"sales_project_id": 5,
"sales_project_name": "name",
"sales_project_est_rev": "123.00",
"project_status": {
"id": 1,
"label": "Start",
"description": null
}
},
{
"sales_project_id": 6,
"sales_project_name": "name2",
"sales_project_est_rev": "123.00",
"project_status": {
"id": 1,
"label": "Start",
"description": null
}
}
],
"2": [],
"4": []
};
const a = Object.values(data)
let res =a.reduce((acc, elem)=>{
elem.forEach((x)=>{
var obj = {
id : x.project_status.id,
title : x.project_status.label,
cards : [{
id: x.sales_project_id,
title: x.sales_project_name
}]
}
acc.columns.push(obj);
})
return acc
},{columns: []});
console.log(res)
This question already has answers here:
Why does a js map on an array modify the original array?
(5 answers)
Updating an array of objects without mutation
(1 answer)
Why does map mutate array of objects?
(3 answers)
Closed 3 years ago.
I have a structure like this:
let MainItem = [
{
"Id": "1",
"Cost": "1000"
},
{
"Id": "2",
"Cost": "5000"
},
{
"Id": "3",
"Cost": "2000"
},
{
"Id": "4",
"Cost": "3000"
}
];
I am going to change the value of Cost each of the elements with map() loop and store it in NewMainItem.
let NewMainItem = MainItem.map((item, i) => {
item.cost = item.cost + 1000
return item
});
console.log(MainItem)
console.log(NewMainItem)
The main problem is that by changing Cost in NewMainItem, the value of
Cost in MainItem will be changed too, but I don not want to do this. By using map() loop why the main object (MainItem ) will be changed too?
You should use map to create new objects from the existing ones, not modify them.
You could use the spread operator to create a new item like this:
{ ...item, Cost: parseFloat(item.Cost) + 100 };
Here parseFloat was used because the Costs values are set as string in your snippet. Feel free to change this as it fits your needs.
See below snippet:
let MainItem = [
{
"Id": "1",
"Cost": "1000"
},
{
"Id": "2",
"Cost": "5000"
},
{
"Id": "3",
"Cost": "2000"
},
{
"Id": "4",
"Cost": "3000"
}
];
let NewMainItem = MainItem.map((item, i) => {
return { ...item, Cost: parseFloat(item.Cost) + 100 };
});
console.log(MainItem)
console.log(NewMainItem)
You could assign a new object with the wanted changed value.
var mainItem = [{ Id: "1", Cost: "1000" }, { Id: "2", Cost: "5000" }, { Id: "3", Cost: "2000" }, { Id: "4", Cost: "3000" }],
newMainItem = mainItem.map(item => Object.assign({}, item, { Cost: +item.Cost + 1000 }));
console.log(mainItem);
console.log(newMainItem);
.as-console-wrapper { max-height: 100% !important; top: 0; }