Add Parent Property to each Objects using FlatMap/Map - javascript

I am trying to achieve the following results in few lines of code.
Expected Result:
[{
active: true,
id: 1,
name: "California",
country: USA
}, {
active: true,
id: 2,
name: "New York",
country:"USA"
},...
{
active: true,
id: 4,
name: "Moscow",
country:"Russia"
}, ....]
This is what I tried but again there is a property country missing in the results. Expecting the shortest & efficient way to achieve this. Thank you for your responses.
const obj = [
{
country: "USA",
cities: ["California", "New York", "Austin"]
},
{
country: "Russia",
cities: ["Moscow", "kazan", "Samara"]
}
];
//here the map of country is not there, wondering how to achieve this.
//obj.map(y => y.country).flatMap(x => x.cities)
const aa = obj.flatMap(x => x.cities)
.map((str, index) => ({ name: str, id: index + 1, active:true}));
console.log(aa)

The problem with Behram's and Ori's above is that the generated index is not correct; it will generate 1,2,3,1,2,3:
Instead remove the index value from the mappers:
let index = 1;
const results = obj.flatMap(({ country, cities }) => cities.map((city) => ({ active: true, id: index++, name: city, country })));
console.log(result)

You'll need another .map to tie each city with its country first.
const obj = [
{
country: "USA",
cities: ["California", "New York", "Austin"]
},
{
country: "Russia",
cities: ["Moscow", "kazan", "Samara"]
}
];
const aa = obj
.flatMap(({ cities, country }) => cities.map(city => ({ name: city, country })))
.map((obj, index) => ({ ...obj, id: index + 1, active:true}));
console.log(aa)
You might consider the imperative version too. While less functional, it's a bit easier to understand.
const obj = [
{
country: "USA",
cities: ["California", "New York", "Austin"]
},
{
country: "Russia",
cities: ["Moscow", "kazan", "Samara"]
}
];
const aa = [];
let id = 1;
for (const { cities, country } of obj) {
for (const name of cities) {
aa.push({ name, country, id: id++, active: true });
}
}
console.log(aa)

function transform(obj) {
let id = 0;
return obj.flatMap(({country, cities}) => cities.map(city => ({active:true, name: city, country,id: ++id})))
}
console.log(transform(obj))
if you want a one-liner you can store that id in a parent anonymous function, ( but I will not suggest this as this is less readable )
console.log(((id) => obj.flatMap(({country, cities}) => cities.map(city => ({active:true, name: city, country,id: ++id}))))(0))

follow this way:
const results = obj.flatMap(({ country, cities }) => {
return cities.map((city, index) => ({
active: true,
id: index + 1,
name: city,
country: country
}));
});
console.log(results);

Related

typescript/js comparing arrays of objects adding new key value

My goal is to compare 2 objects if there is a match between object 1 and 2 using if they have the same id then insert new key value to object 1 which isConfirmed = true to each object that has a match;
Any idea guys ? I provided my current code below. Thanks.
#objects - original data
const object1 = [
{
"id": 10691,
"city": "Morris",
},
{
"id": 10692,
"city": "NY",
]
const object2 = [
{
"id": 10691,
"city": "Morris",
{
"id": 10500,
"city": "JY",
}
]
#ts code
let result = object1.filter(o1 => object2.some(o2 => o1.id === o2.id));
#expected sample result
object1 = [
{
"id": 10691,
"city": "Morris",
"isConfirmed": true,
},
{
"id": 10692,
"city": "NY",
}
]
You can easily achieve the result using Set and map as:
const object1 = [
{
id: 10691,
city: 'Morris',
},
{
id: 10692,
city: 'NY',
},
];
const object2 = [
{
id: 10691,
city: 'Morris',
},
{
id: 10500,
city: 'JY',
},
];
const map = new Set(object2.map((o) => o.id));
const result = object1.map((o) =>
map.has(o.id) ? { ...o, isConfirmed: true } : { ...o },
);
console.log(result);
You can do it by using the snippet
let result = object1.map(o1 =>
object2.some(o2 => o1.id === o2.id)
? {...o1, isConfirmed: true}
: {...o1}
);
Check if object2 array has the object with any id from object1. If so, add isConfirmed: true to it.
const object1 = [
{
id: 10691,
city: 'Morris',
},
{
id: 10692,
city: 'NY',
},
];
const object2 = [
{
id: 10691,
city: 'Morris',
},
{
id: 10500,
city: 'JY',
},
];
let result = object1.map(o1 => object2.some(o2 => o1.id === o2.id) ? {...o1, isConfirmed: true} : {...o1});
console.log(result);

Javascript: How to use map and filter between two array object

I am facing some issue on using .map and .filter where I am unable to get the object which is not similar in two objects.
What changes I need to do to get the uncommon object from arrayObjTwo.
code
const arrayObjOne = [{
countryCode: "US",
description: " Backyard of home",
id: "1234",
location: "US",
name: "Backyard",
}]
// Array Object 2
const arrayObjTwo =[
{ description: "Backyard of home", spaceName: "Backyard" },
{ description: "Frontyard of home", spaceName: "Frontyard"},
]
const object1Names = arrayObjOne.map(obj => obj.Name); // for caching the result
const results = arrayObjTwo.filter(name => !object1Names.includes(name));
console.log(results);
One compiler code: https://onecompiler.com/javascript/3xy92hpmp
expected result:
const arrayObjTwo =[
{ description: "Frontyard of home", spaceName: "Frontyard" }
]
Thanks..
Your filter for the result is wrong. You should be using the "object.spaceName" instead of just "name" as you're looping through an array of objects and not just strings
// So this line:
const results = arrayObjTwo.filter(name => !object1Names.includes(name));
// Should be:
const results = arrayObjTwo.filter(object => !object1Names.includes(object.spaceName));
// And you have a typo:
const object1Names = arrayObjOne.map(obj => obj.Name);
// Should be like so as keys and properties are case-sensitive:
const object1Names = arrayObjOne.map(obj => obj.name);
So this should all be:
const arrayObjOne = [{
countryCode: "US",
description: " Backyard of home",
id: "1234",
location: "US",
name: "Backyard",
}]
// Array Object 2
const arrayObjTwo =[
{ description: "Backyard of home", spaceName: "Backyard" },
{ description: "Frontyard of home", spaceName: "Frontyard"},
]
const object1Names = arrayObjOne.map(obj => obj.name); // for caching the result
const results = arrayObjTwo.filter(object => !object1Names.includes(object.spaceName));
console.log(results);
You're close!
You have capitalized names in your map-statement, but javascript is case-sensitive, so the field you're looking up "Name", does not exist, and as such your "object1Names" returns undefined.
You should be looking up obj.name
You also need to compare it to the arrayObjTwo's "spaceName"-field, not the entire object.
Here's your code with these small changes:
const arrayObjOne = [{
countryCode: "US",
description: " Backyard of home",
id: "1234",
location: "US",
name: "Backyard",
}]
// Array Object 2
const arrayObjTwo =[
{ description: "Backyard of home", spaceName: "Backyard" },
{ description: "Frontyard of home", spaceName: "Frontyard"},
]
const object1Names = arrayObjOne.map(obj => obj.name); // for caching the result
const results = arrayObjTwo.filter(obj => !object1Names.includes(obj.spaceName));
console.log(results);
Do you need this?
const arr1 = [{
countryCode: "US",
description: " Backyard of home",
id: "1234",
location: "US",
name: "Backyard",
}]
// Array Object 2
const arr2 =[
{ description: "Backyard of home", spaceName: "Backyard" },
{ description: "Frontyard of home", spaceName: "Frontyard"},
]
const names = arr1.map(item => item.name); // for caching the result
console.log(names);
const res = arr2.filter(item => !names.includes(item.name));
console.log(res);

How to join .map and .filter to filter and remove duplicate in object array

How to join .map and .filter to filter and remove duplicate in object array?
I currently have to use two variables for this:
Image example
See code Sandbox example
const arrayOne = [
{
id: 1,
name: "João",
city: {
id: 1,
name: "Rio de Janeiro"
}
},
{
id: 1,
name: "Pedro",
city: {
id: 2,
name: "Salvador"
}
},
{
id: 1,
name: "Tiago",
city: {
id: 1,
name: "Rio de Janeiro"
}
}
];
const arrayTwo = arrayOne.map(function (item, index) {
return item.city;
});
const arrayThree = arrayTwo.filter(
(elem, index, arr) => index === arr.findIndex((t) => t.id === elem.id)
);
If your filter is just to remove duplicates consider creating a Map which simply overwrites all duplicate city.ids. This can then be converted back to an array, here using spread syntax on the Map.values().
const arrayOne = [
{ id: 1, name: 'João', city: { id: 1, name: 'Rio de Janeiro' } },
{ id: 1, name: 'Pedro', city: { id: 2, name: 'Salvador' } },
{ id: 1, name: 'Tiago', city: { id: 1, name: 'Rio de Janeiro' } },
];
const arrayTwo = [...new Map(arrayOne.map(({ city }) => [city.id, city])).values()];
console.log(arrayTwo);
Just chain them together?
const result = arrayOne.map(function (item, index) {
return item.city;
}).filter(
(elem, index, arr) => index === arr.findIndex((t) => t.id === elem.id)
);
If you mean that you want to map and filter at the same time, then you can use either flatMap or reduce as described in another Q/A: https://stackoverflow.com/a/34398349/211627

JavaScript string search for array of objects

I need to implement a search function for a table.
I got an array of objects with unnecessary object properties.
I need to map the array to get necessary properties and then do the filtration.
This is my code.
const items = [
{
name: 'pathum',
id: 1,
status: true,
createdAt: 'KKKK',
country: {
name: 'SL',
code: 12,
},
},
{
name: 'kasun',
id: 1,
status: true,
createdAt: 'KKKK',
country: {
name: 'USA',
code: 23,
},
},
{
name: 'hansi',
id: 1,
status: true,
createdAt: 'KKKK',
country: {
name: 'GERMANY',
code: 34,
},
},
];
const tableColumns = ['name', 'country.name'];
const onSearch = (e) => {
e = e.toLowerCase();
const mappedItems = items.map((item) => {
Object.keys(item).forEach((key) => {
if (!tableColumns.includes(key)) delete item[key];
});
return item;
});
if (e) {
const result = mappedItems.filter((item) => {
const str = JSON.stringify(item).toLowerCase();
if (str.search(e) >= 0) return item;
});
return result;
} else {
return mappedItems;
}
};
console.log(onSearch('GERMANY'));
In an item object, I only need to get these two fields
const tableColumns = ['name', 'country.name'];
But this only gives me the name property
const mappedItems = items.map((item) => {
Object.keys(item).forEach((key) => {
if (!tableColumns.includes(key)) delete item[key];
});
return item;
});
My first question is how to map to expect a result like this
{
name: 'pathum',
country: {
name: 'SL',
},
},
Second question is JSON.stringtfy map whole object. So If I search "name" it will return all the objects becasue "name" is there in the all records in the stringtify string.
How do I avoid keys in the object when doing the stringify?
Hope my question is clear to you all.
How do I modify this code to get that expected functionality?
const tableColumns = ['name', 'country'];
const deleteProp = ['code'];
const mappedItems = items.map((item) => {
Object.keys(item).forEach((key) => {
console.log(key);
if (!tableColumns.includes(key)) delete item[key];
if(key == 'country') delete item[key][deleteProp[0]];
});
return item;
});
This may answer your first question.
You can check if the object has any of the tableColumns paths which includes the searched text. And then get a subset of the filtered objects and only include the tableColumns properties
const items=[{name:"pathum",id:1,status:true,createdAt:"KKKK",country:{name:"SL",code:12,},},{name:"kasun",id:1,status:true,createdAt:"KKKK",country:{name:"USA",code:23,},},{name:"hansi",id:1,status:true,createdAt:"KKKK",country:{name:"GERMANY",code:34}}],
tableColumns = ['name', 'country.name'];
function onSearch(array, e) {
const output = [];
for (const o of array) {
const hasProp = tableColumns.some(path => getProperty(o, path).includes(e))
if (hasProp)
output.push(subSet(o, tableColumns))
}
return output
}
function getProperty(o, path) {
return path.split('.').reduce((acc, p) => acc?.[p], o) || ''
}
function subSet(o, paths) {
const output = {}
for (const path of paths) {
let keys = path.split('.'),
last = keys.pop(),
value = o;
const final = keys.reduce((acc, k) => {
value = value?.[k]
return acc[k] ||= {}
}, output);
final[last] = value?.[last];
}
return output;
}
console.log(onSearch(items, 'pat'));
console.log(onSearch(items, 'kasun'));
First, don't change data. You can clone the data and change it.
And, search should be search. Don't put the data formation in it.
Let's start.
const items = [
{
name: 'pathum',
id: 1,
status: true,
createdAt: 'KKKK',
country: {
name: 'SL',
code: 12,
},
},
{
name: 'kasun',
id: 1,
status: true,
createdAt: 'KKKK',
country: {
name: 'USA',
code: 23,
},
},
{
name: 'hansi',
id: 1,
status: true,
createdAt: 'KKKK',
country: {
name: 'GERMANY',
code: 34,
},
},
];
// We will use object to get the fields you want. To reuse, you can add more fields you want.
const tableColumns = {
// id: 1,
name: 1,
country: {
name: 1
}
}
// getting the mapped items
const mappedItems = items.map((item) => {
const temp = {};
Object.keys(item).forEach((key) => {
const target = tableColumns[key];
if (target) {
if (typeof target === 'number'){
temp[key] = item[key];
} else {
temp[key] = {};
Object.keys(target).forEach(subKey => temp[key][subKey] = item[key][subKey]);
}
}
});
return temp;
});
// search function, use local varibles
const onSearch = (array, countryName) => {
return array.find(element => element.country.name.toLowerCase() === countryName.toLowerCase())
}
const searchResult = onSearch(mappedItems, 'germany');
console.log(searchResult);
You can just create a new array using Array.map
const items = [{
name: 'pathum',
id: 1,
status: true,
createdAt: 'KKKK',
country: {
name: 'SL',
code: 12,
},
},
{
name: 'kasun',
id: 1,
status: true,
createdAt: 'KKKK',
country: {
name: 'USA',
code: 23,
},
},
{
name: 'hansi',
id: 1,
status: true,
createdAt: 'KKKK',
country: {
name: 'GERMANY',
code: 34,
},
},
];
let minItems = items.map(function(item) {
return {
"name": item.name,
"country": {
"name": item.country.name
}
}
});
console.log(minItems);

Delete multiple items in one array in react state from another array

I have this array
let deleted = [
{id: '123', name: 'Something'},
{id: '321', name: 'Something1'}
];
and I have this
this.setState({
config: {
...this.state.config,
categories: this.state.config.categories.map(cat => ({
...cat,
movies: [...cat.movies, ...currentMovies]
}))
}
});
Every movies array for every category contains all items from deleted array but are not the same arrays because some contains selected property and some not, but movie id's are the same.
How can I delete every item from delete array from every categories.movies array?
I am thinking to iterate through deleted and then for every item in that array do
movies: this.state.config.categories.filter(item => item.id !== deleted.id)
But i do not know if that's a best solution, can someone help?
Thanks in advance
This should work. filter the movies as well with map.
const filt = (item) => item.id !== deleted.id;
this.state.config.categories.filter(filt).map(({ movies, ...rest }) => ({
...rest,
movies: movies.filter(filt),
}));
It isn't very clear what the state structure is, but to filter the movies array by checking against an array of movies to delete can be done a couple ways using an array::filter function.
Search the deleted array each iteration and check if the movie id's match (O(n) linear search). If no match found then include in the result.
movies.filter(movie => !deleted.some(({ id }) => movie.id === id))
let deleted = [
{ id: "123", name: "Something" },
{ id: "321", name: "Something1" }
];
const currentState = {
movies: [
{ id: "120", name: "Something 120" },
{ id: "121", name: "Something 121" },
{ id: "122", name: "Something 122" },
{ id: "123", name: "Something" },
{ id: "124", name: "Something 124" },
{ id: "125", name: "Something 125" },
{ id: "321", name: "Something1" }
]
};
const nextState = currentState.movies.filter(
movie => !deleted.some(({ id }) => movie.id === id)
);
console.log(nextState)
Create a map of deleted movie ids so you don't have to search each time (O(1) constant-time search).
const deletedMovieIdSet = deleted.reduce((ids, { id }) => {
ids.add(id);
return ids;
}, new Set());
...
movies.filter(movie => !deletedMovieIdSet.has(movie.id))
let deleted = [
{ id: "123", name: "Something" },
{ id: "321", name: "Something1" }
];
const deletedMovieIdSet = deleted.reduce((ids, { id }) => {
ids.add(id);
return ids;
}, new Set());
const currentState = {
movies: [
{ id: "120", name: "Something 120" },
{ id: "121", name: "Something 121" },
{ id: "122", name: "Something 122" },
{ id: "123", name: "Something" },
{ id: "124", name: "Something 124" },
{ id: "125", name: "Something 125" },
{ id: "321", name: "Something1" }
]
};
const nextState = currentState.movies.filter(
movie => !deletedMovieIdSet.has(movie.id)
);
console.log(nextState)

Categories