Reduce javascript object - javascript

I have this javascript object :
{
{
long_name: "10",
types: [
0: "street_number"
],
},
{
long_name: "street",
types: [
0: "route"
],
},
{
long_name: "Paris",
types: [
0: "locality"
],
},
...
}
And I want to flatten it and have something like :
{
street_number: "10",
route: "street",
locality: "Paris",
...
}
I am using ES6, but can't manage to flatten it this much,
All I've succeeded to do is having :
{
{street_number: "10"},
{route: "street"},
{locality: "Paris"},
...
}
Here is what I Tried :
const flattenedObject = originalObject.map(flatten);
...
function flatten(element) {
let obj = {};
obj[element.types[0]] = element.long_name;
return obj;
}
Thanks for any help.

You could use Array#reduce with a computed property and the first element only from the array.
The key feature is Object.assign for adding properties to the result object.
The Object.assign() method is used to copy the values of all enumerable own properties from one or more source objects to a target object. It will return the target object.
var data = [{ long_name: "10", types: ["street_number"], }, { long_name: "street", types: ["route"], }, { long_name: "Paris", types: ["locality"], }],
object = data.reduce((r, a) => Object.assign(r, { [a.types[0]]: a.long_name }), {});
console.log(object);

All I've succeeded to do is having:
{
{street_number: "10"},
{route: "street"},
{locality: "Paris"},
...
}
I don't how you "succeeded" in getting that, since no such kind of object exists in JS (nor does your original object). Did you mean to put [] around it instead of {} (in other words, is it an array of little objects)? If so, then combine with
Object.assign({}, ...littleObjects)
By the way, you can call this "flattening" if you want, but it will be confusing, since it's quite different from what people usually refer to as "flattening" (meaning to collapse nested arrays).

Related

Javascript : Modify object and add new index to a property

My object is something like:
let items =
[
{
"creationTimeStamp": "2022-05-31T17:04:28.000Z",
"modifiedTimeStamp": "2022-05-31T17:04:28.000Z",
"locations": [
{
"id": "5ao",
"name": "Store1"
}
],
"typeId": "Lead"
}
]
I am trying to push the following object into the locations property:
{
"id": "9a0",
"name": "Store2"
}
I have tried doing
items1 = [];
for (var i = 0; i < items.length; i++) {
items1.id = "9a0";
items1.name = "Store2";
//9 is some static index value added
Object.assign({9 : items1}, items[i].locations);
}
If I console(Object.assign({9 : items1}, items[i].locations)); I can see 2 arrays inside it, but my items locations property is still the same.
My expectation is as below:
[
{
"creationTimeStamp": "2022-05-31T17:04:28.000Z",
"modifiedTimeStamp": "2022-05-31T17:04:28.000Z",
"locations": [
{
"id": "5ao",
"name": "Store1"
},
{
"id": "9a0",
"name": "Store2"
}
],
"typeId": "Lead"
}
]
I also tried to use items[i].locations.push(item1) but then got:
TypeError: Cannot add property 9, object is not extensible
I also tried to assign a new array to items[i].locations, but then got:
TypeError: Cannot assign to read only property 'locations' of object '#'
What can I do to get the desired result?
You seem to expect that the second argument given to Object.assign will be mutated. But it is the first argument that is mutated. That means your .locations is not mutated. Moreover, in comments you indicate that locations cannot be extended and that the property is read-only.
So that means you'll need a complete new object.
Some other remarks:
Don't initialise items1 as an array, since it is supposed to be a plain object.
Declare a variable with const, let or var and avoid implicit global declaration.
It is safer to declare the items1 object inside the loop, so you create a new object each time and don't mutate the same object. For your example code it makes no difference, but it can lead to unexpected behaviour.
As you don't need i for anything else than items[i], and you actually need a complete new structure, use .map instead.
So:
items = items.map(item => {
let obj = {
id: "9a0",
name: "Store2"
};
return {...item, locations: item.locations.concat(obj) };
});
I always think in terms of functions, and of immutability-by-default, so my approach might look like this, with addLocationToAll built atop a simpler addLocation. The code is fairly simple:
const addLocation = (newLoc) => ({locations, ...rest}) =>
({...rest, locations: locations .concat (newLoc)})
const addLocationToAll = (newLoc) => (items) =>
items .map (addLocation (newLoc))
const items = [{creationTimeStamp: "2022-05-31T17:04:28.000Z", modifiedTimeStamp: "2022-05-31T17:04:28.000Z", locations: [{id: "5ao", name: "Store1"}], typeId:"Lead"}]
const newLoc = {id: "9a0", name: "Store2"}
console .log (addLocationToAll (newLoc) (items))
.as-console-wrapper {max-height: 100% !important; top: 0}
items is an array so it must access the first position of the array, which would be the proposed object.
With this, from the proposed object you will extract thelocation attribute and since this is an array, you use the push function to insert the new object
items[0]
// ->
// {
// creationTimeStamp: '2022-05-31T17:04:28.000Z',
// modifiedTimeStamp: '2022-05-31T17:04:28.000Z',
// locations: [ { id: '5ao', name: 'Store1' } ],
// typeId: 'Lead'
// }
I try this:
items[0].locations.push({"id": "9a0", "name": "Store2" })
And now:
items[0]
//->
// {
// creationTimeStamp: '2022-05-31T17:04:28.000Z',
// modifiedTimeStamp: '2022-05-31T17:04:28.000Z',
// locations: [ { id: '5ao', name: 'Store1' }, { id: '9a0', name: 'Store2' }],
// typeId: 'Lead'
// }

Creating a nested Json from an array

I have this Js array:
const a = [
[
"Paris",
"75000"
],
[
"Toulouse",
"31000"
],
[
"Marseille",
"13000"
]
];
How to convert restructure this array to JSON?
[{
"city": "Paris",
"zip": "75000"
},
{
"city": "Toulouse",
"zip": "31000"
},
{
"city": "Marseille",
"zip": "13000"
}]
I tried with the JSON.stringify() function but I don't get the expected result.
Thanks
Youre array declaration isn't correct. This is the correct syntax for declaring an array in JS and using JSON.stringify on it:
tab = [
{city: 'Paris', zip: '75000'},
{city: 'Toulouse', zip: '31000'},
{city: 'Marseille', zip: '13000'}
];
JSON.stringify(tab, null, 2)
You could use Array.prototype.map to convert sub-array entries of the original array into objects with suitably named properties, and call JSON.stringify on the result.
const tabs = [
[
"Paris",
"75000"
],
[
"Toulouse",
"31000"
],
[
"Marseille",
"13000"
]
];
// restructure sub-arrays into objects:
let objectArray = tabs.map(entry=> {
const [city, zip] = entry;
return {city, zip};
})
// Stringify object array
let jsonText = JSON.stringify( objectArray, null, 2)
console.log(jsonText);
The map function is using Destructuring assignment to extract city and zip values from each sub-array.
A null second and numeric third parameter supplied to JSON.stringify improve human readability of the output but are generally omitted in production environments to reduce the length of network messages.

Maintaining order of items in the map function: Javascript

I am trying to use the map to change the one of the field name , but I see the order of items are getting changed .
var arrOfObj = [
{
name: "test1",
value: "value1"
},
{
name: "test2",
value: "value2"
}
];
function changeKeyName(arr, oldValue, newVal) {
return arr.map(item => {
item[`${newVal}`] = item[`${oldValue}`];
delete item[`${oldValue}`];
return item;
});
}
console.log(changeKeyName(arrOfObj, "name", "type"));
Is there any way I can maintain the order of items along with changing of one of the field names.
O/P:
[{type:"test1",value: "value1"}, {type: "test2", value:"value2"}]
Thanks in advance
You can use Object.entries to take an array of entries, then map them, replacing the old key with the new key when found:
var arrOfObj = [
{
name: "test1",
value: "value1"
},
{
name: "test2",
value: "value2"
}
];
const changeKeyName = (arr, oldKey, newKey) => arr.map(
item => Object.fromEntries(
Object.entries(item).map(
([key, val]) => [key === oldKey ? newKey : key, val]
)
)
);
console.log(changeKeyName(arrOfObj, "name", "type"));
(Contrary to popular belief, object property order is guaranteed by the specification, and has been implemented in all environments for years. But keep in mind that this will only work for keys which aren't array indicies - array indicies like 0 1 2 can't be ordered relative to other properties, they'll always be iterated over first, in ascending numeric order)
That said, code is generally easier to understand if it's written such that property order doesn't matter - if you have code that depends on the properties being in a particular order, I'd recommend refactoring it so that the property order doesn't matter.
map is being used incorrectly here as you should always return a new set of results from that.
You can do this and you can change the order as required:
const arrOfObj = [
{
name: "test1",
value: "value1"
},
{
name: "test2",
value: "value2"
}
];
function changeKeyName(arr, oldValue, newVal) {
return arr.map(({ [oldValue]: val, ...rest }) => {
return {
[newVal]: val,
...rest,
};
});
}
console.log(changeKeyName(arrOfObj, "name", "type"));

Loop through an array of objects and get where object.field equals value

I'm currently working on a small application where I have to loop through an enormous array of objects. What would be the most efficient method to perform this?
var array = [
{
id: "1",
name: "Alpha"
},
{
id: "2",
name: "Beta"
},
...
];
I'd like to get each object where name equals "Alpha". I'm currently using a simple if statement to filter the objects with a different name value out, but I wonder if there's a more efficient way to do this, performance-wise.
It's worth to mention that I'll push the matching results into a new array.
No, there is no more efficient way.
The alternative is to build and maintain some kind of internal data structure which allows you to find the desired elements faster. As usual, the trade off is between the work involved in maintaining such a structure vs the time it saves you.
I don't have any way about which I would know it's more effective.
But if you had your objects ordered by name you could stop your search imideatly upon reaching an object whose name is not equal to "Alpha".
To find the first object you're looking for you can use binary search and from this Object you go up and down until at both ends you reach an object which isn't named "Alpha" or the end of array.
This is only a way of optimizing and will require time to sort the array and also will take more time when adding an element.
There's a JavaScript function exactly for this kind of task. Filter
From the Docs
The filter() method creates a new array with all elements that pass the test implemented by the provided function.
Here is a small example by code for getting all element from array which has a certain 'name' field:
const arr = [
{name: 'Abc'},
{name: 'Xyz'},
{name: 'Lmn'},
{name: 'Xyz'},
{name: 'Xyz'}
];
let response = findByName('Xyz');
console.log(response);
function findByName (name) {
return arr.filter((element) => {
return element.name = name;
});
}
If you need more than one time a collection with a given name, you could use an object with the names as hashes and have instantly access to the items.
var array = [{ id: "1", name: "Alpha" }, { id: "2", name: "Beta" }, { id: "3", name: "Beta" }, { id: "4", name: "Gamma" }, { id: "5", name: "Beta" }, { id: "2", name: "Alpha" }],
hash = Object.create(null);
array.forEach(function (a) {
if (!hash[a.name]) {
hash[a.name] = [];
}
hash[a.name].push(a);
});
console.log(hash);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Convert Javascript response to Array/Map

I have the following response from a Javascript ElasticSearch Query, and i need to map it to the below structure. Is there a more efficient way to do this than what I am currently doing?
Thanks
Structure I need to map to: (about 700 of these)
[{
"coordinates": ["48", "37"],
"name": "something",
"population": "501"
},
Current structure of my data being returned:
[Object, Object, Object, Object, Object, Object, Object, Object, Object, Object]
0: Object
_id: "4"
_index: "locationIndex"
_score: 1
_source: Object
coordinates: Array[2]
0: -77.080597
1: 38.892899
length: 2
__proto__: Array[0]
name: "someName"
population: 57205
1: Object
...
What I'm trying but fails:
var results= [{
"key": 'coordinates',
resp.coordiantes[0],
resp.coordinates[1],
"key": 'name',
resp.name
})
}];
Assuming that your data is stored inside a myData variable, you can use the Array.prototype.map method to manipulate it and achieve what you want. Here's a solution:
result = myData.map(function(obj) {
return {
coordinates: obj._source.coordinates,
name: obj.name,
population: obj.population
}
});
Simple as this! The result will be something like this:
[
{
"coordinates": [-77.080597, 38.892899],
"name": "some name",
"population": 52701
},
{
"coordinates": [-54.930299, 30.992833],
"name": "some name 2",
"population": 84229
},
{
"coordinates": [-82.001438, -5.38131],
"name": "some name 3",
"population": 5991
} //, ...
]
It looks like you don't quite understand Object syntax in Javascript; in order for my answer to make the most sense, you may wish to read up a little on them.
Now that you understand Objects more, it should become quite clear that what you want looks something like:
var results = [];
for (var i = 0, len = data.length; i < len; i++)
{
var resp = data[i];
results.push({
'coordinates':resp['source']['coordinates'],
'name':resp.name,
'population':resp.population
});
}
For bonus points, you could include a JS framework like jQuery and just uase a map function.
I like Marcos map solution the most but also possible and quick is to use Array.from(data). This helped me in the past to convert the response API data that should be an array but wasn't yet.
I am the author of the open source project http://www.jinqJs.com.
You can easily do something like this to do what you want.
var result = jinqJs().from(data5).select(function(row){
return {coordinates: [row.coordinates[0]['0'], row.coordinates[0]['1']],
name: row.name,
population: row.population
}
});

Categories