mapping through the array of arrays ReactJS / JS - javascript

I have the following code.
I have this array of array data.
const data = [
[
{
city: "Phnom Penh",
country: "KH"
},
{
city: "Tirana",
country: "AL"
},
{
city: "Andorra la Vella",
country: "AD"
}
],
[
{
city: "Mariehamn",
country: "AX"
}
],
[]
];
I am trying to print all city in the new variable and then want to show in select
const cities = data.map((el) => el).map((el, idx) => el[idx]?.city);
<select>
{cities.map((el) => (
<option value={el} key={idx}>
{el}
</option>)}
</select>
But I am getting only first city.
The output now is
(3) ["Phnom Penh", undefined, undefined]
But the output should be
(4) ["Phnom Penh", "Tirana", "Andorra la Vella", "Mariehamn"]
Please help me to correct my code.
Thanks.

I fixed your code
For an easy way to understand what's going on, I divided it into two variables.
const a = data.flatMap((num) => num);
const b = a.map((el) => el.city);
And then you can show it in your select tag

const cities = data.flat().map(item => item.city);
The flat() method creates a new array with all sub-array elements concatenated into it recursively up to the specified depth.
The Javascript map() method in JavaScript creates an array by calling a specific function on each element present in the parent array. It is a non-mutating method. Generally, the map() method is used to iterate over an array and calling function on every element of the array.
console.log(cities);
// Output: ["Phnom Penh", "Tirana", "Andorra la Vella", "Mariehamn"]

Since flat may not be available on every environment I am providing with an alternative solution:
let cities = [];
data.forEach(el=> {
el.forEach(element => {
cities.push(element.city);
});
});

Related

Get values from objects in array with rest parameter

let newValues = user.info.socialMedia ? [...user.info.socialMedia] : []
So here we get several objects into the array that have an id key, and instead of the objects themselves I want to have only the id strings in this array. How can I get this working? I am quite new to Javascript, so it would be nice to get some help here.
I tried a for of then a for in loop to get the ids out of there and push them to the array, tho this does not work for my case.
instead of the objects themselves I want to have only the id strings
That sounds like a .map() operation, to project one array into another by applying a transformation to each object. Something like this:
let newValues = user.info.socialMedia ? user.info.socialMedia.map(s => s.id) : []
Or perhaps simpler:
let newValues = user.info.socialMedia?.map(s => s.id) ?? []
For example:
let user = {
info: {
socialMedia: [
{ id: 1, name: 'Ron' },
{ id: 2, name: 'Tammy' },
{ id: 3, name: 'Tammy 2' }
]
}
};
let newValues = user.info.socialMedia?.map(s => s.id) ?? []
console.log(newValues);

javascript find() in nested array

I'm trying to build a website with REACT. In the homepage you have 2 buttons, europe and usa.
Let's say you click europe. Then you see a list of all the countries in europe.
And when you click a country, you should see a list of CITIES in that country.
The question is, how can I access the items inside "cities"?.
const DATA = [
{
id: 1,
title: "EUROPE",
countries: [
{
id: 1,
country: "france",
cities: [
{
id: 1,
city: "paris"
},
{
id: 2,
city: "toulouse"
}
];
// so at homepage, you click "europe", and on the second page i got this:
const StateCard = () => {
const { title } = useParams();
const selectedData = DATA.find( d => d.title === title);
return(
<div className="main">
{selectedData &&
selectedData.countries.map((item, id) => {
return (
<div className="card-container" >
<Link key={id} to={`${title}/${item.country}`}> {item.country} </Link>
</div>
);
})}
</div>
useParams gives us back the title that added to the URL after the first click,
which is "europe".
selectedData gives us back the items inside "europe":
{id: 1, title: "EUROPE", countries: Array(1)}
and now the screen shows "france". you clicked france, and now i wanna show the 2 cities inside.
all i got is:
const { country } = useParams();
which gives us "france".
but i dont know how to access the cities inside.
i tried to play with DATA.countries.find(), but whatever i put after DATA. gives me
"TypeError: Cannot read property 'find' of undefined".
sorry its so long thanks guys!
Each type (continents, countries, cities) is an array. find won't work on DATA.countries because countries is a property of whatever continent object you select.
It may help you to divide up your data collections using a series of methods. getContinents gets the data as an argument, and the value of title. getCountries receives the array returned by getContinents - as well as the value of country - and returns its own array of countries, and then getCities maps over that data to return the city names.
This way you maintain a series of data collections, and the code is easier to maintain.
const data = [{"id":1,"title":"EUROPE","countries":[{"id":1,"country":"france","cities":[{"id":1,"city":"paris"},{"id":2,"city":"toulouse"}]}]}];
const title = 'EUROPE';
const country = 'france';
const getContinents = (data, val) => data.find(obj => obj.title === title)
const getCountries = (data, val) => data.countries.find(obj => obj.country === val)
const getCities = (data) => data.cities.map(obj => obj.city);
// Pass in the data and the value of title
const continents = getContinents(data, title);
// Use the array returned from `getContinents` and the country value
const countries = getCountries(continents, country);
// Use the array returned from `getCountries`
const cities = getCities(countries);
console.log(cities);
You can first find the Country and then on countriesResult you can find citiesResult and then can find cities from citiesResult.cities.
You're getting the error **TypeError: Cannot read property 'find' of undefined** because
what you're doing is DATA.countries.find(). Data is an array so you can't use .countries on it. You have to find the country using find or use index.
const DATA = [{
id: 1,
title: "EUROPE",
countries: [{
id: 1,
country: "france",
cities: [{
id: 1,
city: "paris",
},
{
id: 2,
city: "toulouse",
},
],
}, ],
}, ];
const title = "EUROPE";
const country = "france";
const countriesResult = DATA.find((d) => d.title === title);
const citiesResult = countriesResult.countries.find(
(c) => c.country === country
);
const result = citiesResult.cities.map((c) => c.city);
console.log(result);
DATA is an array of objects. Each item in DATA have countries array. So, you have to use find() on specific item in DATA array, and not on DATA array iteself. For example, you can do this:
DATA[0].countries.find()

creating object from multiple array properties

I am looping through an object that contains multiple telephone numbers as keys and arrays with objects as values.
I have written a reduce method that groups all of the schedules together, except for one issue.
if you run the snippet you see that res is:
{trackingNumber: [ [Array] ]}
I need the object to look like:
{trackingNumber: [Array]}
The issue I continue to run into is trying to pop or slice or do anything by initial index makes the first array that is concatted (Object.values(res)) basically it enumerates the first object of that array as the first 7 elements of the value associated with tracking number.
{trackingNumber: [0:string, 1:string, 2:string, 3: {object of strings in 0 1 and 2}]}
Any help would be appreciated.
let todayNewTollFree = [
{paymentSchedule: [{amount:500},{amount:500},{amount:500},{amount:500},{amount:500},{amount:500},],
tracking: "+18003160182"},
{paymentSchedule: [{amount:500},{amount:500},{amount:500},{amount:500},{amount:500},{amount:500},{amount:500},],
tracking: "+18003160182"
},
{
paymentSchedule: [],
tracking: "+12134105385"
},
{
paymentSchedule: [{amount:500},{amount:500},{amount:500},{amount:500},],
tracking: "+18007084605"
},
{
paymentSchedule:[{amount:500},{amount:500},{amount:500},{amount:500},{amount:500},],
tracking: "+18007100629"
}
]
let test = todayNewTollFree.reduce(function (res, obj) {
let key = obj.tracking;
if (res[key]) {
res[key] = res[key].map((key) =>
[key].flat().concat(obj.paymentSchedule)
);
} else res[key] = [obj.paymentSchedule];
for (const tracking in res) {
let values = Object.values(res[key]).flat();
console.log(tracking);
console.log(values);
}
return res;
}, {});
console.log(test)
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
The for in loop creates a flat array correctly but every attempt I have to go back and call or assign tracking to the newly created array isn't working.
When adding a new key to the object, you should not place it inside an array literal [...] (as that creates an array whose first element is an array) and should simply assign the array itself to the property. Furthermore, when adding to an array, Array#map is not necessary and Array#concat will do the job.
let todayNewTollFree = [ {paymentSchedule: [{amount:500},{amount:500},{amount:500},{amount:500},{amount:500},{amount:500},], tracking: "+18003160182"}, {paymentSchedule: [{amount:500},{amount:500},{amount:500},{amount:500},{amount:500},{amount:500},{amount:500},], tracking: "+18003160182" }, { paymentSchedule: [], tracking: "+12134105385" }, { paymentSchedule: [{amount:500},{amount:500},{amount:500},{amount:500},], tracking: "+18007084605" }, { paymentSchedule:[{amount:500},{amount:500},{amount:500},{amount:500},{amount:500},], tracking: "+18007100629" } ]
let test = todayNewTollFree.reduce(function (res, obj) {
let key = obj.tracking;
if (res[key]) {
res[key] = res[key].concat(obj.paymentSchedule)
} else res[key] = obj.paymentSchedule;
return res;
}, {});
console.log(test)

_.map doesn't return an array of objects, but strings

I have an array of objects:
[{name:'john',age: 24}, {name:'arian', age: 34}]
I want to get the following array back:
[{title:'john'},{title:'arian'}]
The following code:
let tableData = {
header: [{title: 'name'}],
data: _.map(groups, group => {
return group.name
})
};
results in: ['john', 'arian']
but this code:
let tableData = {
header: [{title: 'name'}],
data: _.map(groups, group => {
return {title: group.name} // <-- this line changed
})
};
returns an array of length 0 for data. Why does this happen ? isn't it basically the same ?
Update 1
How I get groups:
const { groups } = this.props;
This is a react code.
The problem stated has a very simple solution. You are doing it right, but need little change in the code
var obj = [{name:'john',age: 24}, {name:'arian', age: 34}];
var result = _.map(obj,(value)=>{
return {name:value.name};
});
If you are expecting each member of your resultant array to be a object then you need to return that kind of object from your map, as simple as that. Either you use lodash or pure javascript version of map, answer is the same:
_.map(groups, o=>({'title': o.name}))
Or with native javascript Array map
groups.map(o=>({'title': o.name}))
Why not use native Array.prototype.map?
let data = [{name:'john',age: 24}, {name:'arian', age: 34}]
console.log(data.map( (item) => { return { title: item.name } }))

Object.assign and ... spread operator fail silent, don't add elements

I have problems with Object.assign and ... spread operator. I need to process values (object with name and value tha are objects).
Example my values object:
{
id: "12",
name: "Hotel MESSI",
email: "myemail#aol.com",
phone: "+001060666661",
otherfields: "{
country: 'ZW',
city: 'Zurick'
}"
}
otherfields comes from graphql , so it's string, i must convert to object.
With my process I look for this result:
{
id: "12",
name: "Hotel MESSI",
email: "myemail#aol.com",
phone: "+001060666661",
country: 'ZW',
city: 'Zurick'
}
The code have more code that I paste here, there is a lot of controls for values and conversion but mainly, the idea is reassing values,
With these two case assign to the same variable is not working:
Case 1, with object.assign
processValues = (values)=>
let newValues = {...values}; //
for (const fieldName in Tables[table].fields) {
let value = values[fieldName];
value = JSON.parse(value);
newValues = { ...newValues, ...value};
console.error('after mix',newValues);
Case 2, with object.assign
processValues = (values)=>
let newValues = Object.assign({}, values}; //
for (const fieldName in Tables[table].fields) {
let value = values[fieldName];
value = JSON.parse(value);
newValues = Object.assign( newValues, value};
console.error('after mix',newValues);
How it's works, when I use a new variable, by example:
newValues2 = Object.assign( newValues, value};
but my idea is not use another variable because , i need to get values and set values for the original variable 'newValues' , if I use another variable the code would be more cumbersome.
I'm using in a project with create-react-app. I don't know if it's a problem with babel, because Object.assign and spread operator are not inmmutable; or yes ?
INFO:
Tables[table].fields is a object with definition por my table structure, there therea lot of rules, but basically i need to know why object and ... does not work
The use of JSON.stringify will not help, as this will produce a JSON string, which will have an entirely different behaviour when spreading it (you get the individual characters of that string).
Here is how you can achieve the result with "otherfields" as the special field (you can add other fields in the array I have used):
const processValues = values =>
Object.assign({}, ...Object.entries(values).map( ([key, val]) =>
["otherfields"].includes(key) ? val : { [key]: val }
));
// Example:
const values = {
id: "12",
name: "Hotel MESSI",
email: "myemail#aol.com",
phone: "+001060666661",
otherfields: {
country: 'ZW',
city: 'Zurick'
}
};
const result = processValues(values);
console.log(result);
The first argument to assign is the target. So it's going to get changed. You can simply pass an empty object for your target if you don't want any of the sources to change.
When you are using first argument as {} then no value will change.
For more please refer it.
https://wecodetheweb.com/2016/02/12/immutable-javascript-using-es6-and-beyond/

Categories