Transform json array of objects - javascript

I have a json with "proceds" and "teams".
Id´like to transform it grouping it by team.
Next, I show a snippet what I want achieve.
How can I do it?
dados:{
proceds:[
{id:'1', proc:'11', teams:[{team_id:1},{team_id:2}]},
{id:'2', proc:'12', teams:[{team_id:1},{team_id:3}]},
{id:'3', proc:'13', teams:[{team_id:2},{team_id:3}]},
]
}
I´d like to transform "dados" to:
dados:{
teams:[
{team_id:1, proceds:[{id:'1', proc:'11'},{id:'2', proc:'12'}],
{team_id:2, proceds:[{id:'1', proc:'11'},{id:'3', proc:'13'}]
{team_id:3, proceds:[{id:'2', proc:'12'},{id:'3', proc:'13'}]
]
}

You can create an object lookup for each team id and then generate the result using Object.entries and array#map.
const data = [ {id:'1', proc:'11', teams:[{team_id:1},{team_id:2}]}, {id:'2', proc:'12', teams:[{team_id:1},{team_id:3}]}, {id:'3', proc:'13', teams:[{team_id:2},{team_id:3}]}, ],
result = Object.entries(data.reduce((r, o) => {
o.teams.forEach(({ team_id }) => {
r[team_id] = r[team_id] || [];
r[team_id].push({ id: o.id, proc: o.proc });
});
return r;
}, {})).map(([team_id, proceds]) => ({ team_id, proceds }));
console.log(result);
.as-console-wrapper{min-height:100% !important; top: 0; }

You need to iterate each object to make groups.
let dados = {
proceds:[
{id:'1', proc:'11', teams:[{team_id:1},{team_id:2}]},
{id:'2', proc:'12', teams:[{team_id:1},{team_id:3}]},
{id:'3', proc:'13', teams:[{team_id:2},{team_id:3}]},
]
};
const groupByTeams = [];
dados.proceds.forEach(item=> {
let {teams, ...teamItems} = item;
teams.forEach(team=>{
groupByTeams.find(x=>x.team_id==team.team_id)?groupByTeams.find(x=>x.team_id==team.team_id).proceds.push({...teamItems}):groupByTeams.push({...team, proceds: [{...teamItems}]});
});
});
console.log({dados:{teams:groupByTeams}});

You can combine reduce with Object.keys
const asObject = dados.proceds.reduce((acc, curr) => {
curr.teams.forEach(t => acc[t.team_id] = [...(acc[t.team_id] || []), { id: curr.id, proc: curr.proc }])
return acc
}, {})
const result = {
teams: Object.keys(asObject).map(k => ({ team_id: k, proceds: asObject[k] }))
}

const dados = {
proceds:[
{id:'1', proc:'11', teams:[{team_id:1},{team_id:2}]},
{id:'2', proc:'12', teams:[{team_id:1},{team_id:3}]},
{id:'3', proc:'13', teams:[{team_id:2},{team_id:3}]},
]
}
function transform(object) {
object.teams = object.proceds.map((obj) => ({
team_id: parseInt(obj.id),
proceds: [
...obj.teams.map(team => ({
id: team.team_id.toString(),
proc: object.proceds.find(proc => proc.id == team.team_id).proc
}))
]
}))
delete object.proceds;
return object;
}
console.log(transform(dados))

Related

Filter object of object of array properties by key javascript

I have this objects i want to filter articles by news ,funny and sports
const articles = {
article_1: {
tags: ['news', 'funny']
},
article_2: {
tags: ['sports', 'funny']
}
}
i want to filter to have result
const articlesByTag = groupArticlesByTag(articles);
articlesByTag = {
news: ['article 1'],
funny: ['article 1', 'article 2'],
sports: ['article 2']
}
You can easiy achieve this result using Object.entries, reduce and forEach.
const articles = {
article_1: {
tags: ["news", "funny"],
},
article_2: {
tags: ["sports", "funny"],
},
};
function groupArticlesByTag(obj) {
return Object.entries(obj).reduce((acc, [key, val]) => {
val.tags.forEach((tag) => {
if (acc[tag]) {
acc[tag].push(key);
} else {
acc[tag] = [key];
}
});
return acc;
}, {});
}
const articlesByTag = groupArticlesByTag(articles);
console.log(articlesByTag);
You can even make it a bit shorter with Logical nullish assignment (??=)
const articles = {
article_1: {
tags: ["news", "funny"],
},
article_2: {
tags: ["sports", "funny"],
},
};
function groupArticlesByTag(obj) {
return Object.entries(obj).reduce((acc, [key, val]) => {
val.tags.forEach((tag) => {
(acc[tag] ??= []).push(key);
});
return acc;
}, {});
}
const articlesByTag = groupArticlesByTag(articles);
console.log(articlesByTag);
Object.keys() -> gives an array of all the keys of an object.
.forEach() -> iterate through an array of items
If the key already exists then push to the array, otherwise create an array of length 1 with the key.
let groupArticlesByTag = (articles) => {
let articlesMap = {};
Object.keys(articles).map((x) => {
articles[x].tags.forEach((y)=> {
if(articlesMap[y]==undefined){
articlesMap[y] = [x]
}
else{
articlesMap[y].push(x);
}
});
});
return articlesMap;
}

Filter array of objects based on another array

I have a source array and target array, based on the target array need to update the source array
sourceAry = [{name:'Label1', value: 'label1', children:[{name:'Ammu'},{name:'Rahual'},{name:'Anu'}]},
{name:'Label2', value: 'label2', children:[{name:'Hari'},{name:'Tom'}]},
];
targetAry = [{name:'Label1', value: 'label1', children:[{name:'Anu'}]},
{name:'Label2', value: 'label2', children:[{name:'Hari'},{name:'Tom'}]},
];
resultAry = [{name:'Label1', value: 'label1', children:[{name:'Ammu'},{name:'Rahual'}]}
]},
];
Code which I try
let resultAry = sourceAry.map((obj) => {
obj.children.map((elem) =>{
targetAry.filter(parent => parent.children.filter((el) => {
el.name !== elem.name}))
})
})
console.log(resultAry, 'NEW', list);
you could start start with some facilities to make it simpler:
const indexBy = (f, data) => data.reduce((acc, x) => Object.assign(acc, { [f(x)]: x }), {})
const remove = (keyFn, dataToRemove, from) => {
const dataToRemoveIndexed = indexBy(keyFn, dataToRemove);
return from.filter(it => !(keyFn(it) in dataToRemoveIndexed));
}
we introduce the indexBy here, to make removal O(m+n), instead of O(m^2) (if there are many items in the collection to check)
then you can use it like this:
const targetIndexed = indexBy(it => it.name, targetAry);
const result = sourceAry.map(
it => ({
...it,
children: remove(
it => it.name,
(targetIndexed[it.name] || {}).children || [],
it.children
)
})
)
so it leaves you with the following result:
[
{"name":"Label1","value":"label1","children":[{"name":"Ammu"}, {"name":"Rahual"}]},
{"name":"Label2","value":"label2","children":[]}
]
if you also want to delete the item with empty children, you can just filter it out: result.filter(it => it.children.length > 0)
Ciao, try something like this:
sourceAry = [{name:'Label1', value: 'label1', children:[{name:'Ammu'},{name:'Rahual'},{name:'Anu'}]}, {name:'Label2', value: 'label2', children:[{name:'Hari'},{name:'Tom'},{name:'Ammu'},{name:'Rahual'},{name:'Anu'}]}, {name:'Label3', value: 'label3', children:[{name:'Ammu'},{name:'Rahual'},{name:'Anu'}]} ];
targetAry = [{name:'Label1', value: 'label1', children:[{name:'Anu'}]},
{name:'Label2', value: 'label2', children:[{name:'Hari'},{name:'Tom'}]},
];
let result = [];
sourceAry.forEach(source => {
let filter = targetAry.filter(target => target.name === source.name)
if (filter.length > 0) {
let filterchildren = source.children.filter(a => !filter[0].children.map(b=>b.name).includes(a.name));
if (filterchildren.length > 0) {
let resultobj = source;
resultobj.children = filterchildren;
result.push(resultobj);
}
}
else result.push(source);
})
console.log(result)
I filter targetAry based on sourceAry name. Then subtract children with .filter(a => !filter[0].children.map(b=>b.name).includes(a.name)); and finally push element found in result array.

Join array of object to new array object

I have data array object like this:
const data = [
{Name: "dian", Job: "programmer"},
{Name: "dian", Job: "gamer"},
{Name: "candra", Job: "programmer"},
]
My goal is to create new data where a have same value join b.
Example output:
const new_data = [
{Name: "dian", Jobs: [{Job: "programmer"}, {Job: "gamer"}]},
{Name: "candra", Jobs: [{Job: "programmer"}]},
]
I think you can use Array.prototype.reduce() to achive your goal. From the documentation:
The reduce() method executes a reducer function (that you provide) on each element of the array, resulting in a single output value.
One possible solution:
const data = [
{Name:'dian', Job:'programer'},
{Name:'dian', Job:'gamers'},
{Name:'candra', Job:'programer'}
];
const result = data.reduce((a, current) => {
const found = a.find(f => f.Name === current.Name);
if (found) {
found.Jobs.push({Job: current.Job});
} else {
a.push({
Name: current.Name,
Jobs: [
{ Job: current.Job }
]
});
}
return a;
}, []);
console.log(result);
I hope that helps!
use reduce.
const data = [
{ Name: "dian", Job: "programer" },
{ Name: "dian", Job: "gamers" },
{ Name: "candra", Job: "programer" }
];
const output = Object.values(data.reduce((a, { Name, Job }, i) => {
if (!a[Name]) {
a[Name] = { Name, Jobs: [] };
}
a[Name].Jobs.push({ Job });
return a;
}, {}));
console.log(output);
Here's one approach:
const combineJobs = (data) =>
Object .values (data .reduce (
(a, {Name, Job}, _, __, curr = a [Name] || {Name, jobs: []}) =>
({... a, [Name]: ({... curr, jobs: [... curr .jobs, {Job}]})}),
{}
))
const data = [{Name: "dian", Job: "programmer"}, {Name: "dian", Job: "gamer"}, {Name: "candra", Job: "programmer"}]
console .log (combineJobs (data))
We simply fold our objects into a structure that looks like
{
dian: {Name: 'dian', jobs: [Job:'programer'}, {Job: 'gamer'}]},
candra: {Name: 'candra', jobs: [Job:'programer'}]},
}
then use Object .values to turn it into an appropriate array.
One advantage of this technique is that if your data actually has additional fields not displayed in the question (imagine you have age, and avatar properties as well, for instance), you can extend it easily using a rest parameter:
const combineJobs = (data) =>
Object .values (data .reduce (
(a, {Name, Job, ...rest}, _, __, curr = a [Name] || {Name, jobs: [], ...rest}) =>
// ^^^^^^^ ^^^^^^^
({... a, [Name]: ({... curr, jobs: [... curr .jobs, {Job}]})}),
{}
))
and all those additional parameters would be included.
function modifyArray(data) {
function getNewObject(data) {
const newObject = {
Name: data.Name
};
Object.keys(data).filter(key => key !== 'Name').forEach(key => {
newObject[key+'s'] = [];
newObject[key+'s'].push({
[key]: data[key]
});
});
return newObject;
}
function appendData(obj, data) {
Object.keys(data).filter(key => key !== 'Name').forEach(key => {
obj[key+'s'].push({
[key]: data[key]
});
});
}
const reqArray = [];
data.forEach(d => {
const objToModify = reqArray.find(a => a.Name === d.Name);
if (!objToModify) {
reqArray.push(getNewObject(d));
} else {
appendData(objToModify, d);
}
});
return reqArray;
}
let data =[
{Name:'dian', Job:'programer' },
{Name:'dian', Job:'gamers' },
{Name:'candra', Job:'programer' }
];
console.log(modifyArray(data));

Map Javascript array of countries into new array

Alright, so I have a package react-country-region-selector that provides me with an array CountryRegionData, when I console log it, it's an array of 248 countries,
As you can see in the image for Italy for example, 0 is country name, 1 is country code, 2 is an string of cities seperated by an | and their codes seperated by an ~.
what I would like to do is map this array into a new one, where for each entry it's reformatted to have 3 properties,
country_name using the value in 0
country_code using the value in 1
cities containing an array which has a sub-array for each city that has city_name using the value before the ~ and city_code containing the value after the ~.
I understand this is a bit overwhelming but I'm hoping it would be possible to do using a map function.
Thank you.
You can get the desired structure by mapping over the array itself and mapping over cities of every country inside the arary:
const CountryRegionData = [['Andorra', 'AD', 'Andorra la Vella~07|Canillo~02'], ['Angola', 'AO', 'Bengo~BGO|Benguela~BGU']];
const result = CountryRegionData.map(([country_name, country_code, cities]) => ({
country_name,
country_code,
cities: cities
.split('|')
.map(cityData => cityData.split('~'))
.map(([city_name, city_code]) => ({ city_name, city_code }))
}));
console.log(result)
Here is a destructing version that creates an object array as I assume you meant
let res = [
["Italy", "IT", "Abruzzo~65|Basilicata~77|Calabria~89"],
["Italy2", "IT2", "Abruzzo~65|Basilicata~77|Calabria~89"],
["Italy3", "IT3", "Abruzzo~65|Basilicata~77|Calabria~89"],
["Italy4", "IT4", "Abruzzo~65|Basilicata~77|Calabria~89"],
].map(item => {
const [country_code, country_name, ...rest] = item;
return {country_code, country_name, cities :
rest.map(item => {
return item.split("|").map(city => {
const [city_name, city_code] = city.split("~")
return {city_name, city_code}
})
}).flat()
}
});
console.log(res)
The quick and dirty version...
const rawCountries = [['Italy', 'IT', 'Abruzzo~65|Basilicata~77']];
const countries = rawCountries.map(rawCountry => ({
country_name: rawCountry[0],
country_code: rawCountry[1],
cities: rawCountry[2].split('|').map(rawCity => {
const cityTuple = rawCity.split('~');
return { city_name: cityTuple[0], city_code: cityTuple[1] };
})
}));
console.log(countries);
Should be more maintainable over time...
const rawCountries = [['Italy', 'IT', 'Abruzzo~65|Basilicata~77']];
const parseCountries = (() => {
return (rawCountries) => rawCountries.map(parseCountry);
function parseCountry(rawCountry) {
return {
country_name: rawCountry[0],
country_code: rawCountry[1],
cities: parseCities(rawCountry[2])
};
}
function parseCities(rawCities) {
return rawCities.split('|').map(parseCity);
}
function parseCity(rawCity) {
const countryCodeTuple = rawCity.split('~');
return {
city_name: countryCodeTuple[0],
city_code: countryCodeTuple[1]
};
}
})();
console.log(parseCountries(rawCountries));
Here is a clean and simple solution to this:-
function formatCountries(countryArray) {
var result = [];
countryArray.forEach(country => {
result.push({ country_name: country[0], country_code: country[1], cities: getCities(country[2]) });
});
return result;
}
function getCities(cityStr) {
const cityAndCodeArr = cityStr.split('|');
const result = [];
cityAndCodeArr.forEach(item => {
const tempArr = item.split('~');
result.push({ city_name: tempArr[0], city_code: tempArr[1]});
});
return result;
}
// call the formatCountries function like following
formatCountries(data);
You can use a combination of array reduce and array map to create a new country array
let originalArray = <Your array>
let newCountryArray = originalArray.reduce((newArray, currentElement) => {
let newObj = {};
newObj.country_name = currentElement[0];
newObj.country_code = currentElement[1];
let cities = currentElement[2];
cities = cities.split('|');
cities = cities.map(city => {
city = city.split('~');
return {
city_name: city[0],
city_code: city[1]
};
});
newObj.cities = cities;
newArray.push(newObj);
return newArray;
}, []);
I have made a working snippet for you. You can customize the variables acording to your needs.
let ar = [
["Italy", "IT", "Abruzzo~65|Basilicata~77|Calabria~89"],
["Italy2", "IT2", "Abruzzo~65|Basilicata~77|Calabria~89"],
["Italy3", "IT3", "Abruzzo~65|Basilicata~77|Calabria~89"],
["Italy4", "IT4", "Abruzzo~65|Basilicata~77|Calabria~89"],
]
let newAr = ar.map((x) => {
let cities = x[2].split("|");
let citiesAr = cities.map((y) => {
city = y.split("~");
return {
city_name: city[0],
city_code: city[1]
};
})
return {country_name: x[0], country_code: x[1], cities: citiesAr}
})
console.log(newAr)
let ar = [
["Italy", "IT", "Abruzzo~65|Basilicata~77|Calabria~89"],
["Italy2", "IT2", "Abruzzo~65|Basilicata~77|Calabria~89"],
["Italy3", "IT3", "Abruzzo~65|Basilicata~77|Calabria~89"],
["Italy4", "IT4", "Abruzzo~65|Basilicata~77|Calabria~89"],
]
let newCountryList = [];
ar.reduce((arr, curr) => {
// debugger;
let newContList = {
country_name: curr[0],
country_code: curr[1],
cities: []
}
let newCities = [];
curr[2].split('|').reduce((ar1, ele) => {
let city = ele.split('~');
newCities.push({ city_name: city[0], city_code: city[1] })
}, [])
newContList.cities = newCities;
newCountryList.push(newContList);
}, [])
console.log(newCountryList)
hope this helps...
Yep, the map function.
const CountryRegionData = [
["Italy", "IT", "Abruzzo~65|Basilicata~77|Calabria~89"],
["Italy2", "IT2", "Abruzzo~65|Basilicata~77|Calabria~89"],
["Italy3", "IT3", "Abruzzo~65|Basilicata~77|Calabria~89"],
["Italy4", "IT4", "Abruzzo~65|Basilicata~77|Calabria~89"],
];
const mappedCountries = CountryRegionData.map(data => {
const cityArray = data[2]
.split('|')
.map(item => {
const cities = item.split('~');
return {
city_name: cities[0],
city_code: cities[1]
}
});
return {
country_name: data[0],
country_code: data[1],
cities: cityArray
};
});
console.log(mappedCountries);
You can do this way using the map function of the array :
// Data set
const data = [
["Italy", "IT", "Abruzzo~65|AnotherCity~70"],
["Spain", "SP", "City~12|AnotherCity~3"],
]
// Declare the variable that will contain the formatted data
const formattedData = data.map((e) => {
// Split the cities string in order to get an array ["Abruzzo~65",
// "AnotherCity~70]"]
let citiesArray = e[2].split('|')
// Map other this array and split around the "~" to get city name
// and city code in an array ["Abruzzo", "65"]
const cities = citiesArray.map((e) => {
return {
city_name: e.split('~')[0],
city_code: e.split('~')[1]
}
})
return {
country_name: e[0],
country_code: e[1],
cities: cities
}
})
console.log(formattedData)

Filter Object Array values based on user input

I want to filter the object array values based on user input.
This is the jsfiddle:
// Copied from https://github.com/tc39/proposal-object-values-entries/blob/master/polyfill.js
const reduce = Function.bind.call(Function.call, Array.prototype.reduce);
const isEnumerable = Function.bind.call(Function.call, Object.prototype.propertyIsEnumerable);
const concat = Function.bind.call(Function.call, Array.prototype.concat);
const keys = Reflect.ownKeys;
if (!Object.values) {
Object.values = function values(O) {
return reduce(keys(O), (v, k) => concat(v, typeof k === 'string' && isEnumerable(O, k) ? [O[k]] : []), []);
};
}
// Copied code ends here;
let data = {
Belgien: [{
code: "BRU",
name: "Bryssel",
aliases: "Bryssel,BRU,Belgien"
}],
Cypern: [{
code: "LCA",
name: "Larnaca",
aliases: "Larnaca,LCA,Cypern,Ayia Napa,Protaras,Fig Tree Bay,Larnaca"
},
{
code: "PFO",
name: "Paphos",
aliases: "Paphos,PFO,Cypern"
}
]
}
let userInput = "lar";
let filteredData = Object.values(data).map(values => values.filter(value =>
value.name.toLowerCase().indexOf(userInput) !== -1));
console.log(filteredData);
The issue is that I get the values properly filtered, but I do not get the keys associated with these values, in this example the countries.
Thanks in advance.
You can use the function reduce and filter the data using the functions filter and indexOf.
This alternative uses the function Object.keys to be able to recover the desired key.
let data = { Belgien: [{ code: "BRU", name: "Bryssel", aliases: "Bryssel,BRU,Belgien" }], Cypern: [{ code: "LCA", name: "Larnaca", aliases: "Larnaca,LCA,Cypern,Ayia Napa,Protaras,Fig Tree Bay,Larnaca" }, { code: "PFO", name: "Paphos", aliases: "Paphos,PFO,Cypern" } ]},
userInput = "lar",
filteredData = Object.keys(data).reduce((a, k) => {
a[k] = data[k].filter(({name}) => name.toLowerCase().indexOf(userInput) > -1);
return a;
}, {});
console.log(filteredData);
.as-console-wrapper { max-height: 100% !important; top: 0; }
You could iterate over the keys and return an object with only filtered data.
var data = { Belgien: [{ code: "BRU", name: "Bryssel", aliases: "Bryssel,BRU,Belgien" }], Cypern: [{ code: "LCA", name: "Larnaca", aliases: "Larnaca,LCA,Cypern,Ayia Napa,Protaras,Fig Tree Bay,Larnaca" }, { code: "PFO", name: "Paphos", aliases: "Paphos,PFO,Cypern" }] },
userInput = "lar",
filteredData = Object.keys(data).reduce((r, k) => {
var temp = data[k].filter(({ name }) => name.toLowerCase().includes(userInput));
if (temp.length) {
r[k] = temp;
}
return r;
}, {});
console.log(filteredData);
.as-console-wrapper { max-height: 100% !important; top: 0; }
You could get the job done using Object.entries like this:
let filteredData = Object.entries(data).reduce((acc, values) => {
const value = values[1].filter(value =>
value.name.toLowerCase().indexOf(userInput) !== -1),
key = values[0];
acc[key] = value;
return acc;
}, {});

Categories