Related
I'm looking for a way in javascript to transform this json to something else.
{
"John Doe": {
"place": "Amsterdam"
},
"Jane Doe": {
"place": "Paris"
}
}
To something like this:
{
{ "id": 0,
"name": "John Doe",
"place": "Amsterdam"
},
{ "id": 1,
"name": "Jane Doe",
"place": "Paris"
},
}
How can I achieve this with javascript?
You can use Object.entries to get key/value pair and use map method to transform the object into the new one.
const data = {
"John Doe": {
"place": "Amsterdam"
},
"Jane Doe": {
"place": "Paris"
}
}
const result = Object.entries(data).map(([key, value], index) => ({
id: index,
name: key,
place: value.place
}))
console.log(result)
You can map the entries to objects. You can mix destructuring and object property shorthand to simplify this greatly.
Note: Order is not guaranteed when iterating through an object's keys.
const obj = {
"John Doe": { "place": "Amsterdam" },
"Jane Doe": { "place": "Paris" },
};
const list = Object.entries(obj)
.map(([name, { place }], id) =>
({ id, name, place }));
console.log(list);
.as-console-wrapper { top: 0; max-height: 100% !important; }
I am trying to figure out the most performant Javascript way to convert an array of objects, into an object with unique keys and an array full of objects as the value.
For Example:
const array = [
{ "name": "greg", "year": "2000" },
{ "name": "john", "year": "2002" },
{ "name": "bob", "year": "2005" },
{ "name": "ned", "year": "2000" },
{ "name": "pam", "year": "2000" },
];
I would like this converted to:
{
"2000": [
{ "name": "greg", "year": "2000" },
{ "name": "ned", "year": "2000" },
{ "name": "pam", "year": "2000" }
],
"2002": [ { "name": "john", "year": "2002" } ],
"2005": [ { "name": "bob", "year": "2005" } ],
}
As of now, this is what I've done so far:
let yearsObj = {};
for (let i=0; i<array.length; i++) {
if (!yearsObj[array[i].year]) {
yearsObj[array[i].year] = [];
}
yearsObj[array[i].year].push(array[i]);
}
you can use a more elegant way to do it by using array's reduce function
// # impl
const group = key => array =>
array.reduce(
(objectsByKeyValue, obj) => ({
...objectsByKeyValue,
[obj[key]]: (objectsByKeyValue[obj[key]] || []).concat(obj)
}),
{}
);
// # usage
console.log(
JSON.stringify({
byYear: group(array),
}, null, 1)
);
// output
VM278:1 {
"carsByBrand": {
"2000": [
{
"name": "greg",
"year": "2000"
},
{
"name": "ned",
"year": "2000"
},
{
"name": "pam",
"year": "2000"
}
],
"2002": [
{
"name": "john",
"year": "2002"
}
],
"2005": [
{
"name": "bob",
"year": "2005"
}
]
}
}
It could be as simple as that Object.fromEntries(array.map(obj => [obj.year,obj])) even it is not exactly what you need, but talking about performance it is way slower than all proposed, so i'm giving it as an bad example of showing how the short statement is not always the fastest.
Your way seems to be the fastest taking about performance.
Run the snippet below to see the actual timing.
// common
let array = [
{ "name": "greg", "year": "2000" },
{ "name": "john", "year": "2002" },
{ "name": "bob", "year": "2005" },
{ "name": "ned", "year": "2000" },
{ "name": "pam", "year": "2000" },
];
// simple as a statement way
console.time();
console.log(Object.fromEntries(array.map(obj => [obj.year,obj])));
console.timeEnd();
// using .reduce way
console.time();
const result = array.reduce((prev, curr) => {
const { year } = curr;
if (prev[year]) {
prev[year].push(curr);
} else {
prev[year] = [curr];
}
return prev;
}, {});
console.log(result);
console.timeEnd();
// your way
console.time();
let yearsObj = {};
for (let i=0; i<array.length; i++) {
if (!yearsObj[array[i].year]) {
yearsObj[array[i].year] = [];
}
yearsObj[array[i].year].push(array[i]);
}
console.log(yearsObj);
console.timeEnd();
A for loop (imperative style) like you have is likely to be the fastest in most situations. However, in this case you are not likely to see much of a difference. One thing you could do to improve the code in your example is to get the array length before the for loop and assign it to the variable, so that it's not calculated every iteration of the loop.
const yearsObj = {};
const arrayLength = array.length; // Only calculate array length once
for (let i=0; i<arrayLength; i++) {
if (!yearsObj[array[i].year]) {
yearsObj[array[i].year] = [];
}
yearsObj[array[i].year].push(array[i]);
}
In this situation, my preference would be to use Array.reduce(). It is more readable and the performance difference will be negligible.
const arr = [
{ name: 'greg', year: '2000' },
{ name: 'john', year: '2002' },
{ name: 'bob', year: '2005' },
{ name: 'ned', year: '2000' },
{ name: 'pam', year: '2000' },
];
const result = arr.reduce((prev, curr) => {
const { year } = curr;
if (prev[year]) {
prev[year].push(curr);
} else {
prev[year] = [curr];
}
return prev;
}, {});
/* Result:
{ '2000':
[ { name: 'greg', year: '2000' },
{ name: 'ned', year: '2000' },
{ name: 'pam', year: '2000' } ],
'2002': [ { name: 'john', year: '2002' } ],
'2005': [ { name: 'bob', year: '2005' } ] }
*/
I have an array of (could be more than this), that has a uid and a timestamp.
My goal is to cycle through an object and if their uid is equal to each other, only keep the object with the greater timestamp.
[
{
"uid":"u55555",
"timestamp":1536273731,
"id":"8a655addf1293b6d780ff6469c0848dd",
"name":"John Doe",
},
{
"uid":"u55555",
"timestamp":1536273831,
"id":"8v8799817981mcmccm89c81282128cm2",
"name":"John Doe",
},
{
"uid":"u1111",
"timestamp":1536253940,
"id":"c8898202n2nu929n2828998228989h2h2",
"name":"Test Testerson",
},
{
"uid":"u55555",
"timestamp":1536274940,
"id":"fb990b1734e4aaea2e39315952e13123",
"name":"John Doe",
},
{
"uid":"u11111",
"timestamp":1538275741,
"id":"99s9hshs88s8g89898899898897a79s",
"name":"Test Testerson",
},
]
Does anyone know how I would do this?
I've been playing around with the following but can't get it just right.
var result = signatures.filter(function (a) {
//logic here
}, Object.create(null));
You could sort the original array by timestamp and then reduce it to only a set of unique uids using sort and reduce.
var data = [{"uid": "u55555","timestamp": 1536273731,"id": "8a655addf1293b6d780ff6469c0848dd","name": "John Doe",}, { "uid": "u55555", "timestamp": 1536273831, "id": "8v8799817981mcmccm89c81282128cm2", "name": "John Doe", }, { "uid": "u1111", "timestamp": 1536253940, "id": "c8898202n2nu929n2828998228989h2h2", "name": "Test Testerson", }, { "uid": "u55555", "timestamp": 1536274940, "id": "fb990b1734e4aaea2e39315952e13123", "name": "John Doe", }, { "uid": "u11111", "timestamp": 1538275741, "id": "99s9hshs88s8g89898899898897a79s", "name": "Test Testerson", }];
var result = data
.sort((a,b) => b.timestamp - a.timestamp) //Sort by timestamp descending
.reduce((a,i) => a.some(n=>n.uid === i.uid) ? a : [...a, i], []); //If item is already accounted for, ignore it
console.log(result);
You can create an object keyed to the guid and loop through your array adding the item to the object if it either isn't already there or the time is smaller. Then just take the values from that object:
let arr = [{"uid":"u55555","timestamp":1536273731,"id":"8a655addf1293b6d780ff6469c0848dd","name":"John Doe",},{"uid":"u55555","timestamp":1536273831,"id":"8v8799817981mcmccm89c81282128cm2","name":"John Doe",},{"uid":"u1111","timestamp":1536253940,"id":"c8898202n2nu929n2828998228989h2h2","name":"Test Testerson",},{"uid":"u55555","timestamp":1536274940,"id":"fb990b1734e4aaea2e39315952e13123","name":"John Doe",},{"uid":"u11111","timestamp":1538275741,"id":"99s9hshs88s8g89898899898897a79s","name":"Test Testerson",},]
let newArr = Object.values(
arr.reduce((obj, item) => {
if (!obj[item.uid] || obj[item.uid].timestamp < item.timestamp)
obj[item.uid] = item
return obj
}, {}))
console.log(newArr)
You could find the object and check the timestamp or add the actual object to the result set.
var array = [{ uid: "u55555", timestamp: 1536273731, id: "8a655addf1293b6d780ff6469c0848dd", name: "John Doe" }, { uid: "u55555", timestamp: 1536273831, id: "8v8799817981mcmccm89c81282128cm2", name: "John Doe" }, { uid: "u1111", timestamp: 1536253940, id: "c8898202n2nu929n2828998228989h2h2", name: "Test Testerson" }, { uid: "u55555", timestamp: 1536274940, id: "fb990b1734e4aaea2e39315952e13123", name: "John Doe" }, { uid: "u11111", timestamp: 1538275741, id: "99s9hshs88s8g89898899898897a79s", name: "Test Testerson" }],
result = array.reduce((r, o) => {
var index = r.findIndex(({ uid }) => uid === o.uid);
if (index === -1) {
return r.concat(o);
}
if (o.timestamp > r[index].timestamp) {
r[index] = o;
}
return r;
}, []);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
This creates a new Object, which uses keys based on the UID; then populates it with only the last entries. Perhaps not the smallest code possible, but it's a method.
let sorted = {};
let original = [{
"uid": "u55555",
"timestamp": 1536273731,
"id": "8a655addf1293b6d780ff6469c0848dd",
"name": "John Doe",
},
{
"uid": "u55555",
"timestamp": 1536273831,
"id": "8v8799817981mcmccm89c81282128cm2",
"name": "John Doe",
},
{
"uid": "u11111",
"timestamp": 1536253940,
"id": "c8898202n2nu929n2828998228989h2h2",
"name": "Test Testerson",
},
{
"uid": "u55555",
"timestamp": 1536274940,
"id": "fb990b1734e4aaea2e39315952e13123",
"name": "John Doe",
},
{
"uid": "u11111",
"timestamp": 1538275741,
"id": "99s9hshs88s8g89898899898897a79s",
"name": "Test Testerson",
},
];
original.forEach((item) => {
if (sorted[item.uid] == undefined || sorted[item.uid].timestamp < item.timestamp) {
// if key doesn't exist, create it
// if key exists but timestamp is newer, replace it
sorted[item.uid] = {
uid: item.uid,
timestamp: item.timestamp,
id: item.id,
name: item.name
}
}
});
console.log(sorted);
Is there a way/function(s) in lodash to get the object's parent of a particular pet id without having to write code that would loop over each person/pet?
For example: _.getParent(people, pets.id => 11) // returns {"type":"Fish", "id":11}.
let people = [
{
"name": "Jack",
"pets": [
{ "type":"Frog", "id":23 },
{ "type":"Bird", "id":57 },
{ "type":"Fish", "id":11 }
]
},
{
"name": "Dawn",
"pets": [
{ "type":"Lion", "id":89 },
{ "type":"Duck", "id":51 }
]
},
{
"name": "Anne"
},
{
"name": "Josh",
"pets": []
}
]
For example,
_.filter(
_.flatMap(people, 'pets'),
t => t && t.id === 11
)
I want to sort some Object look likes this
data = {
"imH3i4igFNxM3GL": {
"name": "Nacky",
"age": 12
},
"vuzPuZUmyT8Z5nE": {
"name": "Emmy",
"age": 20
},
"OkIPDY1nGjxlq3W": {
"name": "Nat",
"age": 20
}
}
I want to sort it by "name".
I tried to use Lodash for this problem.
_.sortBy(data, [function(o) { return o.name; }]);
but, it return me an array of objects without the keys
[
{
"name": "Emmy",
"age": 20
},
{
"name": "Nacky",
"age": 12
},
{
"name": "Nat",
"age": 20
}
]
I want it return me sorted object with key like the same
{
"vuzPuZUmyT8Z5nE": {
"name": "Emmy",
"age": 20
},
"imH3i4igFNxM3GL": {
"name": "Nacky",
"age": 12
},
"OkIPDY1nGjxlq3W": {
"name": "Nat",
"age": 20
}
}
what should I do? thanks
Objects in JS can't be sorted, and the order of the properties is not reliable, ie it depends on browsers' implementations. That's why _.sortBy() is converting your object into a sorted array.
I can think of 2 options to work with that.
Add the key to the objects in the array
If you just need an ordered array with the keys in the objects, so you can render a list.
var data = {
"imH3i4igFNxM3GL": {
"name": "Nacky",
"age": 12
},
"vuzPuZUmyT8Z5nE": {
"name": "Emmy",
"age": 20
},
"OkIPDY1nGjxlq3W": {
"name": "Nat",
"age": 20
}
};
var result = _(data)
.map(function(v, k) { // insert the key into the object
return _.merge({}, v, { key: k });
})
.sortBy('name') // sort by name
.value();
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>
Create an order array
Create an array of ordered keys, and use them when you wish to render the objects in order.
var data = {
"imH3i4igFNxM3GL": {
"name": "Nacky",
"age": 12
},
"vuzPuZUmyT8Z5nE": {
"name": "Emmy",
"age": 20
},
"OkIPDY1nGjxlq3W": {
"name": "Nat",
"age": 20
}
};
var orderArray = _(data)
.keys() // create an array of keys
.sortBy(function(key) { // sort the array using the original names
return data[key].name;
}) // sort by name
.value();
console.log('The order array', orderArray);
console.log(orderArray.map(function(k) {
return data[k];
}));
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>
I use something like this.
let data = {
'g34ghgj3kj': {
YOUR_KEY: 'g34ghgj3kj',
'key1': false,
'key2': false,
},
'hh334h664': {
YOUR_KEY: 'hh334h664',
'key1': true,
'key2': false,
},
//{...}
};
_.orderBy(data, ['key1', 'key2'], ['desc', 'desc']).reduce((result, value) => {
result[value.YOUR_KEY] = value;
return result;
}, {});