Update objects array from another array - javascript
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));
Related
console.log of array returns undefined
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.
Filtering GeoJSON data using array of values to create Leaflet map
I'm still new to coding so please forgive me if I'm not asking the right questions. I have a JSON file with data from a number of countries and I want to use Leaflet to paint all the countries in that file on a map. To do so I'm using a GeoJSON file containing all the countries of the world, and I want to filter this GeoJSON file by "id" (which is a 3-letter country code) so that it only includes the countries in my array (also 3-letter country code). I used D3.json to get an array of just the country codes from my JSON file, and then looped through that array to get each country in the list to filter my GeoJSON file: d3.json("countryList.json", function(data) { const countries = [...new Set(data.map(d => d.country))]; console.log(countries); for (var i = 0; i < countries.length; i++) { var countryCode = countries[i]; console.log(countryCode); }; I tried this with no luck: L.geoJson(data, { filter: function(feature) } if (feature.id === countryCode) return True } };
You don't need d3 to filter your countries. Also, when you initialize a variable inside a for-loop, it's going to get overwritten unless you break from the loop. Anyways, take this example of filtering a single U.S. state out of 2 states and go from there: var geojson_data = {"type":"FeatureCollection","features":[{"type":"Feature","id":"36","properties":{"name":"New York"},"geometry":{"type":"Polygon","coordinates":[[[-73.343806,45.013027],[-73.332852,44.804903],[-73.387622,44.618687],[-73.294514,44.437948],[-73.321898,44.246255],[-73.436914,44.043608],[-73.349283,43.769761],[-73.404052,43.687607],[-73.245221,43.523299],[-73.278083,42.833204],[-73.267129,42.745573],[-73.508114,42.08834],[-73.486206,42.050002],[-73.55193,41.294184],[-73.48073,41.21203],[-73.727192,41.102491],[-73.655992,40.987475],[-73.22879,40.905321],[-73.141159,40.965568],[-72.774204,40.965568],[-72.587988,40.998429],[-72.28128,41.157261],[-72.259372,41.042245],[-72.100541,40.992952],[-72.467496,40.845075],[-73.239744,40.625997],[-73.562884,40.582182],[-73.776484,40.593136],[-73.935316,40.543843],[-74.022947,40.708151],[-73.902454,40.998429],[-74.236547,41.14083],[-74.69661,41.359907],[-74.740426,41.431108],[-74.89378,41.436584],[-75.074519,41.60637],[-75.052611,41.754247],[-75.173104,41.869263],[-75.249781,41.863786],[-75.35932,42.000709],[-79.76278,42.000709],[-79.76278,42.252649],[-79.76278,42.269079],[-79.149363,42.55388],[-79.050778,42.690804],[-78.853608,42.783912],[-78.930285,42.953697],[-79.012439,42.986559],[-79.072686,43.260406],[-78.486653,43.375421],[-77.966344,43.369944],[-77.75822,43.34256],[-77.533665,43.233021],[-77.391265,43.276836],[-76.958587,43.271359],[-76.695693,43.34256],[-76.41637,43.523299],[-76.235631,43.528776],[-76.230154,43.802623],[-76.137046,43.961454],[-76.3616,44.070993],[-76.312308,44.196962],[-75.912491,44.366748],[-75.764614,44.514625],[-75.282643,44.848718],[-74.828057,45.018503],[-74.148916,44.991119],[-73.343806,45.013027]]]}},{"type":"Feature","id":"48","properties":{"name":"Texas"},"geometry":{"type":"Polygon","coordinates":[[[-101.812942,36.501861],[-100.000075,36.501861],[-100.000075,34.563024],[-99.923398,34.573978],[-99.698843,34.382285],[-99.57835,34.415147],[-99.260688,34.404193],[-99.189488,34.2125],[-98.986841,34.223454],[-98.767763,34.135823],[-98.570593,34.146777],[-98.488439,34.064623],[-98.36247,34.157731],[-98.170777,34.113915],[-98.088623,34.004376],[-97.946222,33.987946],[-97.869545,33.851022],[-97.694283,33.982469],[-97.458774,33.905791],[-97.371143,33.823637],[-97.256128,33.861976],[-97.173974,33.736006],[-96.922034,33.960561],[-96.850834,33.845545],[-96.631756,33.845545],[-96.423633,33.774345],[-96.346956,33.686714],[-96.149786,33.840068],[-95.936185,33.889361],[-95.8376,33.834591],[-95.602092,33.933176],[-95.547322,33.878407],[-95.289906,33.87293],[-95.224183,33.960561],[-94.966767,33.861976],[-94.868182,33.74696],[-94.484796,33.637421],[-94.380734,33.544313],[-94.183564,33.593606],[-94.041164,33.54979],[-94.041164,33.018527],[-94.041164,31.994339],[-93.822086,31.775262],[-93.816609,31.556184],[-93.542762,31.15089],[-93.526331,30.93729],[-93.630393,30.679874],[-93.728978,30.575812],[-93.696116,30.438888],[-93.767317,30.334826],[-93.690639,30.143133],[-93.926148,29.787132],[-93.838517,29.688547],[-94.002825,29.68307],[-94.523134,29.546147],[-94.70935,29.622824],[-94.742212,29.787132],[-94.873659,29.672117],[-94.966767,29.699501],[-95.016059,29.557101],[-94.911997,29.496854],[-94.895566,29.310638],[-95.081782,29.113469],[-95.383014,28.867006],[-95.985477,28.604113],[-96.045724,28.647929],[-96.226463,28.582205],[-96.23194,28.642452],[-96.478402,28.598636],[-96.593418,28.724606],[-96.664618,28.697221],[-96.401725,28.439805],[-96.593418,28.357651],[-96.774157,28.406943],[-96.801542,28.226204],[-97.026096,28.039988],[-97.256128,27.694941],[-97.404005,27.333463],[-97.513544,27.360848],[-97.540929,27.229401],[-97.425913,27.262263],[-97.480682,26.99937],[-97.557359,26.988416],[-97.562836,26.840538],[-97.469728,26.758384],[-97.442344,26.457153],[-97.332805,26.353091],[-97.30542,26.161398],[-97.217789,25.991613],[-97.524498,25.887551],[-97.650467,26.018997],[-97.885976,26.06829],[-98.198161,26.057336],[-98.466531,26.221644],[-98.669178,26.238075],[-98.822533,26.369522],[-99.030656,26.413337],[-99.173057,26.539307],[-99.266165,26.840538],[-99.446904,27.021277],[-99.424996,27.174632],[-99.50715,27.33894],[-99.479765,27.48134],[-99.605735,27.640172],[-99.709797,27.656603],[-99.879582,27.799003],[-99.934351,27.979742],[-100.082229,28.14405],[-100.29583,28.280974],[-100.399891,28.582205],[-100.498476,28.66436],[-100.629923,28.905345],[-100.673738,29.102515],[-100.799708,29.244915],[-101.013309,29.370885],[-101.062601,29.458516],[-101.259771,29.535193],[-101.413125,29.754271],[-101.851281,29.803563],[-102.114174,29.792609],[-102.338728,29.869286],[-102.388021,29.765225],[-102.629006,29.732363],[-102.809745,29.524239],[-102.919284,29.190146],[-102.97953,29.184669],[-103.116454,28.987499],[-103.280762,28.982022],[-103.527224,29.135376],[-104.146119,29.381839],[-104.266611,29.513285],[-104.507597,29.639255],[-104.677382,29.924056],[-104.688336,30.181472],[-104.858121,30.389596],[-104.896459,30.570335],[-105.005998,30.685351],[-105.394861,30.855136],[-105.602985,31.085167],[-105.77277,31.167321],[-105.953509,31.364491],[-106.205448,31.468553],[-106.38071,31.731446],[-106.528588,31.786216],[-106.643603,31.901231],[-106.616219,31.999816],[-103.067161,31.999816],[-103.067161,33.002096],[-103.045254,34.01533],[-103.039777,36.501861],[-103.001438,36.501861],[-101.812942,36.501861]]]}}]} L.geoJSON(geojson_data, { filter: function(feature) { return feature.properties.name === "Texas"; } }).addTo(map);
Using a loop to push to an array which is a value in a Map
I am currently trying to create a function which dynamically changes values of an array in a map. This function is intended to create a new element in the array on each full loop, to represent a new instance to be counted. The function is meant to count how many visitors to a country there are every day. This is done throgh a map, with the keys being the country and the values being a list of visitors. Each element is how many visitors there were in a specific day. Where Map: var countries = new Map(); ('England', [0]); ('France', [0]); ('Spain', [0]); ('Poland', [0]); ('Germany', [0]); ('Russia', [0]); For the code: for(var day = 0; day < daysBack; day++){ var dateToFind = (currentDate.date() + " / " + currentDate.month() + " / " + currentDate.year()); var detectionsOnDate = getActivity(dateToFind ); // Returns an array of locations visited, each visit is a new element // eg. ["France", "France", "England", "France"] for(var detectionLocation of detectionsOnDate){ for(var[location, visits] of countries ){ if(location == detectionLocation){ countries.set(location, visits[day]++); } } } currentDate.subtract(1, 'days'); } The result I am looking for is a map similar to: { ('England', [242,235,853,122,512]); ('France', [241,621,173,173,512]); ('Spain', [62,235,213,465,126]); ('Poland', [734,163,856,354,142]); ('Germany', [234,235,643,237,512]); ('Russia', [174,200,136,107,164]); } In my idea of the logic, this should create a new element in the value every time a new loop of 'day' is done. On each loop of day the same element in the map should be updated. I'm relatively new to JS so I'm sorry if this is an easy fix, still finding my way around. Any help is appriciated. Thanks.
push returns the length of the array. So, a number will be set to each key. Instead, you can concat a new number to the value array and set it to the current key. map.set(key, value.concat(value[i]+1)) and map.set(key, value.concat(0))
How to populate array with multiple data types inside?
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)
Push object into an array
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)