Add key/value pair to object within array of arrays? - javascript

Given the following structure:
const data = {
"show": "Family Guy",
"characters": [
[{name: 'Peter', age: 40, city: 'Quahog'}],
[{name: 'Louis', age: 30}],
[{name: 'Chris', age: 16}],
[{name: 'Stewie', age: 1}]
]
}
How can we add to each character the key/value pair of city: 'Quahog' so the output looks as follows:
const item = {
"show": "Family Guy",
"characters": [
[{name: 'Peter', age: 40, city: 'Quahog'}],
[{name: 'Louis', age: 30, city: 'Quahog'}], // city added
[{name: 'Chris', age: 16, city: 'Quahog'}], // city added
[{name: 'Stewie', age: 1, city: 'Quahog'}] // city added
]
}
We tried using:
let city = data.characters.[0][0].city;
costs = _.map(items, (itemArray) => {
items = _.map(itemArray, (item) => {
if(!item.city) {
item.city = city;
}
});
But it's not working as intended and we can't get the desired output. Any idea how to accomplish this?

Not sure about the reason for having these single item arrays but this solution will do the work (I'll recommend you take a look at the process that creates this data format which is a little weird)
const data = {
"show": "Family Guy",
"characters": [
[{name: 'Peter', age: 40, city: 'Quahog'}],
[{name: 'Louis', age: 30}],
[{name: 'Chris', age: 16}],
[{name: 'Stewie', age: 1}]
]
}
const city = data.characters.find(characters => characters.find(character => character.city))[0].city
const dataWithCities = {
...data,
characters: data.characters.map(characters => characters.map(character => character.city ? character : {...character, city}))
}
console.log(dataWithCities)

Here is another way of doing it with .reduce():
const data = {
"show": "Family Guy",
"characters": [
[{name: 'Peter', age: 40, city: 'Quahog'}],
[{name: 'Louis', age: 30}],
[{name: 'Chris', age: 16}],
[{name: 'Stewie', age: 1}]
]
};
data.characters.reduce((a,c)=>
(c[0].city=a[0].city,a));
console.log(data);
When using .reduce() without a second argument it will pick up the first array element as the initial value which is then used as a template to copy the .city property to all the other elements. The actual return value of the .reduce() method is discarded but the input array itself (data) is modified in the process and is then shown in the console.log() expression.

try this one
let city = data.characters.[0][0].city;
let newdata = [];
data.characters.map(items, (itemArray) => {
items = _.map(itemArray, (item) => {
if(item.city === undefined) {
newdata.push({...item , city});
} else {
newdata.push({...item});
}
})
costs = {...newdata}

You can do this without lodash
const data = {
"show": "Family Guy",
"characters": [
[{name: 'Peter', age: 40, city: 'Quahog'}],
[{name: 'Louis', age: 30}],
[{name: 'Chris', age: 16}],
[{name: 'Stewie', age: 1}]
]
}
const chars = data.characters.map((x)=>{
return {...x[0] , city : x[0].city ? x[0].city : city}
})
const items = {...data , characters : chars};

const { city } = data.characters.find(([item]) => !!item.city?.length)[0];
const newData = {
...data,
characters: data.characters.map(([char]) => [{ ...char, city }])
};

Related

Dynamic Multiple Variable Filter Function

Summary:
Thanks for reading! I'm stuck trying to figure out how to pass multiple variables (of unknown quantity) into an argument that is taking in an array of objects (of unknown quantity) In short: I want to filter out people that don't match all of the criteria listed from within another array (I'm also open to using rest instead of an array).
Code access:
codePen: (its a mess) https://codepen.io/gold240sx/pen/NWXJKLv?editors=0011
Additional code I found helpful for getting the key value pair: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/entries
For this Question I'm using an existing example from: https://sebhastian.com/javascript-filter-array-multiple-values/ :
let filteredPeople = people.filter(function (currentElement) {
return currentElement.country === "America" && currentElement.age <
25; });
console.log(filteredPeople);
This is awesome except its assuming I already know the params I'm seeking to filter by and the elements I'm seeking to look for associated params.
// Object Arrays:
let people = [
{name: "Steve", age: 27, country: "America"},
{name: "Linda", age: 23, country: "Germany"},
{name: "Jimena", age: 29, country: "Spain"},
{name: "Eric", age: 24, country: "England"},
{name: "Jacob", age: 24, country: "America"},
];
let filters = [
{country: "America"},
{Age: 24}
];
// Function: (Attempt)
const filterMatch = {}
const filterThePeople = ((data, filters) => {
filters.forEach(filter => {
//==========get key and value of filter=====================
for (const [key, value] of Object.entries(filter)) {
filterMatch[key] = value
return {key, value}
}
})
data.forEach(person => {
for (const [key2, value2] of Object.entries(data)) {
return {key2, value2}
}
})
})
console.log(filterThePeople(people, filters))
I'm not sure whether to place the "data.forEach..." statement inside the for statement above... I was thinking of placing an if or switch statement saying to look through the array for each key and when it finds a matching key, then it will look at the value of each and if both keys and values match then += to a list... eventually to return the list to the function. (at least that's the solution I imagine in my head. I'm totally open to any and all alternative ways of accomplishing this!)
Filter People that match every filter.. I might add that the naming of the KEY is very important here. In your example you had Age as a capital later. This also allows you to construct filters like this:
let filters = [ {country: "America", age: 24} ];
let people = [ { name: "Steve", age: 27, country: "America", }, { name: "Linda", age: 23, country: "Germany", }, { name: "Jimena", age: 29, country: "Spain", }, { name: "Eric", age: 24, country: "England", }, { name: "Jacob", age: 24, country: "America", }, ];
let filters = [
{country: "America"},
{age: 24}
];
let results = people.filter(p =>
filters.every(f=> Object.keys(f).every(k => p[k] === f[k]))
)
console.log(results);
You can do something like this
let people = [
{name: "Steve", age: 27, country: "America"},
{name: "Linda", age: 23, country: "Germany"},
{name: "Jimena", age: 29, country: "Spain"},
{name: "Eric", age: 24, country: "England"},
{name: "Jacob", age: 24, country: "America"},
];
let filters = [
{country: "America"},
{age: 24}
];
const filtered = people.filter(p => filters.every(f => {
const [key] = Object.keys(f)
return p[key] === f[key]
}))
console.log(filtered)

Remove duplicate objects from an array with Keys

How to filter array of objects by property? for example in this array if two or more objects have same properties like name and lastname I want to remove either of them and leave only unique one in an array. example arr:
[ {name: "George", lastname: "GeorgeLast", age: 12},
{name: "George", lastname: "GeorgeLast", age: 13},
{name: "Bob", lastname: "GeorgeLast", age: 12}]
result should be either
[ {name: "George", lastname: "GeorgeLast", age: 13},
{name: "Bob", lastname: "GeorgeLast", age: 12}]
or
[ {name: "George", lastname: "GeorgeLast", age: 12},
{name: "Bob", lastname: "GeorgeLast", age: 12}]
Apply the technique shown in this answer, which is:
function onlyUnique(value, index, self) {
return self.indexOf(value) === index;
}
...but using findIndex with some criteria rather than just indexOf.
let people = [
{ name: "George", lastname: "GeorgeLast", age: 12 },
{ name: "George", lastname: "GeorgeLast", age: 13 },
{ name: "Bob", lastname: "GeorgeLast", age: 12 }
]
let result = people.filter(
(person, index) => index === people.findIndex(
other => person.name === other.name
&& person.lastname === other.lastname
));
console.log(result);
As for whether it keeps 12-year-old George or 13-year-old George, it is a matter of how findIndex works, which so happens to return the first matching element. So in your example case it will keep 12-year-old George.
The Map object holds key-value pairs and remembers the original insertion order of the keys.
const arr = [
{ name: "George", lastname: "GeorgeLast", age: 12 },
{ name: "George", lastname: "GeorgeLast", age: 13 },
{ name: "Bob", lastname: "GeorgeLast", age: 12 }
];
const newMap = new Map();
arr.forEach((item) => newMap.set(item.name, item));
console.log([...newMap.values()]);
Another solution.
Here you don't need to iterate through the list n*n/2 times (if I count correctly).
On the other hand, this one looks less concise and uses more memory.
Use whichever you prefer.
const arr = [
{name: "George", lastname: "GeorgeLast", age: 12},
{name: "George", lastname: "GeorgeLast", age: 13},
{name: "Bob", lastname: "GeorgeLast", age: 12}
];
const obj = {}
arr.forEach(v => {
if (!obj[v.name]) {
obj[v.name] = {}
}
if (!obj[v.name][v.lastname]) {
obj[v.name][v.lastname] = v;
}
})
const result = [];
Object.values(obj).forEach(nameObj =>
Object.values(nameObj).forEach(surnObj => result.push(surnObj))
);
console.log(result)

Javascript get all values of object

I want to get all name from the array of data. Is there any way to do it without using an iterator?
const data = [
{name: 'Rushabh', age: 22},
{name: 'Bonny', age: 24}
]
console.log(Object.values(data));
Try this:
const data = [
{name: 'Rushabh', age: 22},
{name: 'Bonny', age: 24}
]
const names = data.map(({name}) => name)
console.log(names);
the names will include the list of names.
For getting only a single property, you need to map this property directly.
const
data = [{ name: 'Rushabh', age: 22 }, { name: 'Bonny', age: 24 }],
result = data.map(({ name }) => name); // get only name
console.log(result);
Without some kind of iterator you can not do that. You can use map() with short hand property.
const data = [
{name: 'Rushabh', age: 22},
{name: 'Bonny', age: 24}
]
const name = data.map(({name}) => name);
console.log(name);
Use Array.map() and extract the name property:
const data = [
{name: 'Rushabh', age: 22},
{name: 'Bonny', age: 24}
]
console.log(data.map(x => x.name));
If you are using JQuery, do this:
const data = [
{name: 'Rushabh', age: 22},
{name: 'Bonny', age: 24}
]
var names = $.map( data, function(item, key) { return item.name; } );
// names : ['Rushabh', 'Bonny']

React copy items from one object to another, and see if object exists in current state

In React, I've got two state objects that hold multidimensional data like this:
this.state = {
itemList: [
{Id: 1, Name: "Bob", Age: 50},
{Id: 2, Name: "Fred", Age: 26},
{Id: 3, Name: "Joe", Age: 34},
],
newItemList: [],
}
I want to call a function to add an item from the first list to the second list, using the item's Id. For example:
addItem(1);
addItem(2);
//NEW VALUES:
itemList: [
{Id: 1, Name: "Bob", Age: 50},
{Id: 2, Name: "Fred", Age: 26},
{Id: 3, Name: "Joe", Age: 34},
],
newItemList: [
{Id: 1, Name: "Bob", Age: 50},
{Id: 2, Name: "Fred", Age: 26},
],
I then want to call a second function to search the second list, newItemList, to see if it contains an object by Id. If it does contain that Id, I want to remove the full object. Example:
checkItem(2);
function checkItem(item) {
if(isInNewList(item)) {
//Function checks for item 2 and removes item 2 from list
}
}
//NEW VALUE:
newItemList: [
{Id: 1, Name: "Bob", Age: 50},
],
I've done quite a bit of reading, but can't seem to grasp the concepts to make both of these happen easily. Both itemList and newItemList are stored in the current component's state. Thanks for any help!!
Use findIndex to check if the array contains the element, If it contains the element then use filter function to create a new array which does not include the object with the required id
let itemList = [{
Id: 1,
Name: "Bob",
Age: 50
},
{
Id: 2,
Name: "Fred",
Age: 26
},
{
Id: 3,
Name: "Joe",
Age: 34
},
]
let newItemList = [{
Id: 1,
Name: "Bob",
Age: 50
},
{
Id: 2,
Name: "Fred",
Age: 26
},
]
function searchByIndex(id) {
let getIndex = newItemList.findIndex(item => id === item.Id);
if (getIndex !== -1) {
newItemList = newItemList.filter(item => item.Id !== id)
}
}
searchByIndex(2);
console.log(newItemList)
I think a quite clean solution would be to do these operations with item IDs only
const itemIds = [
{Id: 1, Name: "Bob", Age: 50},
{Id: 2, Name: "Fred", Age: 26},
{Id: 3, Name: "Joe", Age: 34},
].map(item => item.id)
this.state = {
itemIds,
newItemIds: [],
}
const addItem = id => this.setState(
state => ({ newItemIds: state.newItemIds.concat(id) })
)
const removeIfPresent = idToRemove => this.setState({
state => ({ newItemsIds: state.newItems.filter(id => id !== idToRemove) })
)

How to get the index of an object in an array of objects when it matches completely javascript

I have an array of objects and I would like to get the index of the object in the array when I get a match.
I have the array as follows:
let x = [
{name: "emily", info: { id: 123, gender: "female", age: 25}},
{name: "maggie", info: { id: 234, gender: "female", age: 22}},
{name: "kristy", info: { id: 564, gender: "female", age: 26}},
.....
];
Currently I am using indexOf which worked initially and now it doesn't work properly. It returns -1.
let find = {name: "maggie", info: { id: 234, gender: "female", age: 22}};
let index = x.indexOf(find); // should return 1.
The whole should match in the array and should return the index of that object. How can I achieve this? Should I be using some() ?
Thank you
You can use .find instead of indexOf as 2 objects are never equal ( as they point to different reference in memory ) which is what you seem to pass as an argument.
let x = [
{name: "emily", info: { id: 123, gender: "female", age: 25}},
{name: "maggie", info: { id: 234, gender: "female", age: 22}},
{name: "kristy", info: { id: 564, gender: "female", age: 26}}
];
let found = x.find(function(item) {
// you can use the condition here
return item.info.id === 564;
});
console.log(found);
To find the index, you can use .findIndex method instead.
let x = [
{name: "emily", info: { id: 123, gender: "female", age: 25}},
{name: "maggie", info: { id: 234, gender: "female", age: 22}},
{name: "kristy", info: { id: 564, gender: "female", age: 26}}
];
let foundIndex = x.findIndex(function(item) {
// you can use the condition here
return item.info.id === 564;
});
console.log(foundIndex);
Objects cannot be compared by traditional equality in JavaScript. Instead, use the ES6 findIndex method to compare each object's properties with the desired values. Here is an example:
let x = [
{name: "emily", info: { id: 123, gender: "female", age: 25}},
{name: "maggie", info: { id: 234, gender: "female", age: 22}},
{name: "kristy", info: { id: 564, gender: "female", age: 26}}
];
let find = {name: "maggie", info: { id: 234, gender: "female", age: 22}};
let index = x.findIndex(element => element.info.id === find.info.id); // index === 1
The id value seems to be sufficient to identify an object in your scenario; if you need to compare more properties, you could obviously add additional equality checks (e.g., element.name === find.name) with the && operator.
If we live in the _.lodash world than this works since lodash would go deep on objects:
let data = [
{name: "emily", info: { id: 123, gender: "female", age: 25}},
{name: "maggie", info: { id: 234, age: 22, gender: "female"}},
{name: "kristy", info: { id: 564, gender: "female", age: 26}},
];
let find = {name: "maggie", info: { id: 234, gender: "female", age: 22}};
let index = _.findIndex(data, (i) => _.isEqual(i, find))
console.log(index) // 1
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.10/lodash.min.js"></script>
A more brutish approach which obviously it is not performant
and as pointed out wont work if the order of the props is different.
let data = [
{name: "emily", info: { id: 123, gender: "female", age: 25}},
{name: "maggie", info: { id: 234, gender: "female", age: 22}},
{name: "kristy", info: { id: 564, gender: "female", age: 26}},
];
var objectJSONs = data.map((i) => JSON.stringify(i))
let myJSON = JSON.stringify({name: "maggie", info: { id: 234, gender: "female", age: 22}});
let index = objectJSONs.indexOf(myJSON)
console.log(index) // 1
You can make use of underscore _.isEqual for Object comparison and some() or any looping mechanism to iterate the array.
let iFoundIndex = -1;
let bFound = x.some((data,index) => {
if(_.isEqual(data,find){
iFoundIndex = index;
return true;
}
return false;
}
//console.log(iFoundIndex);

Categories

Resources