I am trying to take two pieces of data from an object and push it as a new object into an array. The data is being supplied by an API call to my SQL database. That API call is working correctly and displaying the object in a console table. When the script runs a forEach method to extract the data into its own object and then push that new object to a new array, the new array returns "undefined". Code below:
Example data (only one placeholder entry currently, the events array will be seeded with multiple examples in this format)
events = [{location: "Emergency Shelter", latitude: "37.5434", longitude: "-77.4435"}]
Empty arrays declared and API call functioning properly:
let events = [];
let locations = [];
$.get("/api/events", data => {
for (let i = 0; i < data.length; i++) {
events.push(data[i]);
}
});
console.table displays the object correctly and includes the keys "latitude" and "longitude" with the correct corresponding values
forEach method:
locations = events.forEach(location => {
const coords = {};
coords.latitude = location.latitude;
coords.longitude = location.longitude;
locations.push(coords);
});
console.log("Coordinates list: " + locations);
console.log displays "Coordinates list: undefined"
I feel like I may be missing a return somewhere, but I'm not sure where. I tried adding
return locations;
inside the forEach method but it doesn't change anything (and I believe that would exit my function prior to getting through the entire array). Any help is appreciated!
forEach returns nothing so locations should be undefined. You shouldn't pass return value of forEach to locations
events.forEach(location => {
const coords = {};
coords.latitude = location.latitude;
coords.longitude = location.longitude;
locations.push(coords);
});
console.log("Coordinates list: " + locations);
Also you can use map function.
const events = [
{ location: 'Emergency Shelter', latitude: '37.5434', longitude: '-77.4435' }
];
const locations = events.map(({ latitude, longitude }) => ({
latitude,
longitude
}));
console.log(locations);
Try a map based approach which also would condense your code to ...
const events = [{
location: "Emergency Shelter",
latitude: "37.5434",
longitude: "-77.4435"
}, {
location: "Peopl's Kitchen",
latitude: "36",
longitude: "-78"
}, {
location: "Salvation Army",
latitude: "38",
longitude: "-76"
}];
const locations = events.map(({ latitude, longitude }) => ({ latitude, longitude }));
console.log("Coordinates list: ", locations); // do not concatenate the result.
console.log("Coordinates list: " + locations);
console.log("Coordinates list: " + JSON.stringify(locations));
.as-console-wrapper { min-height: 100%!important; top: 0; }
map creates a new array by iterating another one where each item of the new array equals the return value of the mapping/transforming function which, at each iteration step, does process the current value of the original array.
Related
I want to populate "markers" array that contains object and string. I have another javascript object stored in obj variable and I want to extract data from it and store it into markers array.
I am populating array with following code
for (i = 0; i < obj.results.bindings.length; i++) {
markers[i].content = obj.results.bindings[i].placeName.value;
markers[i].coords.lat = Number(obj.results.bindings[i].lat.value);
markers[i].coords.lng = Number(obj.results.bindings[i].long.value);
}
and markers array looks like this (populated manually, not by for loop)
var markers = [
{
coords:{lat:37.8707,lng:32.5050},
content:'<h1>Mevlana museum</h1>'
},
{
coords:{lat:37.8699,lng:32.4993},
content:'<h1>Kapu Camii</h1>'
},
{
coords:{lat:37.8749,lng:32.4931},
content:'<h1>Karatay Madrasa</h1>'
},
{
coords:{lat:37.8749,lng:32.4931},
content:'<h1>Karatay Madrasa</h1>'
},
{
coords:{lat:37.8749,lng:32.4931},
content:'<h1>Karatay Madrasa</h1>'
}
];
Now when javascript object 'obj' have same number of nested objects as elements of markers it works fine but when 'obj' have more nested objects than markers array has elements problems. I just want to add rest of the nested objects from 'obj' into markers. Why doesn't markers array grow dinamically when I add new elements in the for loop?
How about this?
Array should not grow dynamically. You could use push/pop method.
markers = [];
for (i = 0; i < obj.results.bindings.length; i++) {
markers.push({
content : obj.results.bindings[i].placeName.value,
coords : {
lat : Number(obj.results.bindings[i].lat.value),
lng : Number(obj.results.bindings[i].long.value)
}
})
}
I try again with your code below:
for (i = 0; i < obj.results.bindings.length; i++) {
markers[i] = {};
markers[i].content = obj.results.bindings[i].placeName.value;
markers[i].coords= {};
markers[i].coords.lat = Number(obj.results.bindings[i].lat.value);
markers[i].coords.lng = Number(obj.results.bindings[i].long.value);
}
I guess that you didn't assign the type as object, so it went wrong.
Please let me know if this works too.
You can use forEach of your obj.results.bindings then construct each and every markers that you want and eventually push into the array as below
let obj = {
results: {
bindings: [
{ placeName: 'cali', lat: '123', long: '456' },
{ placeName: 'hawaii', lat: '555', long: '333'},
{ placeName: 'korea', lat: '777', long: '888' }]
}
};
let markers = [];
obj.results.bindings.forEach(item => {
let mar = { content: '', coords: {}};
mar.content = item.placeName;
mar.coords.lat = Number(item.lat);
mar.coords.lng = Number(item.long);
markers.push(mar)
})
console.log(markers)
I have requirement like need to form object as below
[
{
"place": "Royal Palace, Oslo",
"latitude" : "59.916911"
},
{
"place": "Royal Palace, Oslo",
"latitude" : "59.916911"
}
]
the above place and latitude values are available within map function as
let sampleArray = [];
jsonresponse.map((item) => {
let place = item.place;
let latitude = {/*with other logic function we will get latitude value*/}
//need to send these both values into below array to form array shown as above.
sampleArray.push();
})
thanks in advance.
You are using the map function wrong.
In a map function, you create a new array in which for each value the return value replaces the current value.
Your function isn't returning new values, and isn't pushing anything to the array. So you have 2 options:
//FIRST OPTION
const sampleArray = jsonResponse.map(({ place } => ({
place,
latitude: [SOME_VALUE]
}))
//SECOND OPTION
const sampleArray = [];
jsonresponse.forEach(({ place }) => {
sampleArray.push({
place,
latitude: [SOME_VALUE]
})
})
Also, notice the es6 destructuring syntax, it could save you some code.
All you need to do with Array.prototype.map is:
let sampleArray = jsonresponse.map((item) => {
let place = item.place;
let latitude = {/*with other logic function we will get latitude value*/}
return {
place,
latitude
}
})
Is this what you want to accomplish ?
let sampleArray = []
jsonresponse.map(item => {
sampleArray.push({
place: item.place,
latitude: {/*with other logic function we will get latitude value*/}
})
})
console.log(sampleArray)
When I shift the tempArr, async.eachSeries will actually skip coordinates (or it seems like coordinatesArr is getting shifted as well). I think it has to do with the pointers pointing to objects with the same memory location, but I have no concept of how that works. What is actually happening when I assign values to variables?
The code will work if I do
tempArr = _.toArray(coordinates);
instead of
tempArr = coordinatesArr;
Sample below:
var coordinatesArr, tempArr;
var marginLon = [];
var marginLat = [];
var coordinates = {
'0': { lon: 13.18472, lat: 32.88972 },
'1': { lon: 13.400454, lat: 32.767144 },
'2': { lon: -120.59234, lat: 47.372269 },
'3': { lon: 122.065977, lat: -26.471618 },
'4': { lon: 122, lat: -25 }
}
coordinatesArr = _.toArray(coordinates);
tempArr = coordinatesArr;
// Will work if changed to below
// tempArr = _.toArray(coordinates);
async.eachSeries(coordinatesArr, function(set, acb) {
tempArr.shift();
if(tempArr.length < 1) return acb();
async.eachSeries(tempArr, function(set2, aacb) {
marginLon.push(Math.abs(set.lon - set2.lon));
marginLat.push(Math.abs(set.lat - set2.lat));
aacb();
}, function(err) {
if(err) return acb();
acb();
});
}, function(err) {
if(err) return;
return;
});
Thank you
All variables can ultimately only contain scalar (non-compound) values. However some of those values are simply references objects (e.g. pointers to object or array). You must recognize when you need a copy of the data that you can modify while retaining the original.
first question why don't you start with an array?
var coordinatesArr = [
{ lon: 13.18472, lat: 32.88972 },
{ lon: 13.400454, lat: 32.767144 } // etcetera
]
secondly, shift is a destructive operation, if tempArr and coordinatesArr both point to the same physical array, modifying one modifies both.
You need something like the line below to create a modifiable array that doesn't harm the orginal:
var tempArr = coordinatesArr.slice();
This is my array:
var country = ["US(+1)","IND(+91)"];
And i want to convert my array in this below format:
country = [
{
title: "US(+1)",
},
{
title: "IND(+91)",
}
]
word title should be same for each array value.
with this code am trying to get my expected result as above
var obj = country.reduce(function(o, val) { o['title'][] = val; return o; }, {});
But my output is comes like this as below: only last index is taking place
{"title":"IND(+91)"} this is wrong output which i dont want
You may be able to do it with reduce but it's much easier to use map:
var country = ["US(+1)","IND(+91)"];
var obj = country.map(function(c){return {title:c}});
console.log("country:", country);
console.log("obj:", obj);
map is for when you want to turn an array of things into another array of things, and reduce is when you want to turn an array of things into just a single thing.
var country = ["US(+1)","IND(+91)"];
I would use a more descriptive word since it is a list of countries.
var countries = ["US(+1)","IND(+91)"];
But to answer your question, to manipulate an array into a new array, I like to use the array.map method:
var objects = countries.map(function(country){ return { title: country } });
Here is the documentation for map:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map?v=control
My main task is to update the markers on the map.
Notation:
Markers that are displayed in real-time on the map:
var markers = [
{ 'lat':10, 'lng':10, 'type':'simple'},
{ 'lat':20, 'lng':20, 'type':'simple'},
{ 'lat':40, 'lng':40, 'type':'cluster'}
]
New markers which should be on the map:
var newMarkers = [
{ 'lat':10, 'lng':10, 'type':'simple'},
{ 'lat':20, 'lng':20, 'type':'simple'},
{ 'lat':30, 'lng':30, 'type':'simple'},
{ 'lat':50, 'lng':50, 'type':'simple'}
]
Thus the problem is reduced to the subtask which I want to find solution:
update the array of objects - markers from the another array of objects - newMarkers.
Thus, need to perform the following manipulation with markers array:
Remove objects from markers which are not in newMarkers (compared by three properties: lat, lng, type).
Add objects from newMarkers into markers if not exist (compared by lat, lng). If marker exist (by two properies: lat, lng) is necessary to update it, i.e. to replace by a new marker from newMarkers.
My solution ineffective since it is because it is performed for a long time on large number of markers.
Updated markers array should look like:
console.log(markers)
{ 'lat':10, 'lng':10, 'type':'simple'},
{ 'lat':20, 'lng':20, 'type':'simple'},
{ 'lat':30, 'lng':30, 'type':'simple'},
{ 'lat':50, 'lng':50, 'type':'simple'}
Just to re-state what was clarified in the comments after the question...
The 1st element in each of markers and newMarkers are equal by value but not by reference, and that matters. Thus you want all the items from newMarkers in your updated list, but if an element in newMarkers has all the same property values as an already existing element in markers then you want to keep the original element from markers.
The solution below loops through all the values in newMarkers and, if an element in markers has the same property values, the markers reference is used, otherwise the newMarkers reference is used.
const markers = [
{ 'lat':10, 'lng':10, 'type':'simple'},
{ 'lat':20, 'lng':20, 'type':'simple'},
{ 'lat':40, 'lng':40, 'type':'cluster'}
];
const newMarkers = [
{ 'lat':10, 'lng':10, 'type':'simple'},
{ 'lat':20, 'lng':20, 'type':'simple'},
{ 'lat':30, 'lng':30, 'type':'simple'},
{ 'lat':50, 'lng':50, 'type':'simple'}
];
const updatedMarkers = newMarkers.map(newMarker =>
markers.reduce((accumulator, origMarker) => (
(
origMarker.lat === newMarker.lat &&
origMarker.lng === newMarker.lng &&
origMarker.type === newMarker.type
) ? origMarker : accumulator
), newMarker)
);
markers.map((marker, idx) => {
console.log(`Element #${idx} from markers is present: ${!!(updatedMarkers.indexOf(marker) + 1)}`);
});
newMarkers.map((marker, idx) => {
console.log(`Element #${idx} from newMarkers is present: ${!!(updatedMarkers.indexOf(marker) + 1)}`);
});
If I'm understanding your problem correctly, you want to reflect changes in newMarkers in markers without simply replacing the reference on markers.
// remove (everything in markers that's not in newMarkers) from markers
_.pull(markers, ..._.difference(markers, newMarkers));
// push (everything in newMarkers that's not in markers) to markers
markers.push(..._.difference(newMarkers, markers));