This is my code I have successfully sorted and got my final result to be what I wanted. Now I want to also sort so that the object name that contains the key word "newitem" will always get sorted to the bottom.
var testgogo = {
"newitemwrewt": {
"brand": {
"gdhshd": true
},
"stock": 2,
"sold": 3
},
"other": {
"brand": {
"gdhshd": true
},
"stock": 2,
"sold": 3
},
"newitemncnc": {
"brand": {
"gdhshd": true
},
"stock": 2,
"sold": 3
},
};
finalresult = Object
.keys(testgogo)
.sort(
(a, b) =>
(testgogo[a].stock !== undefined) - (testgogo[b].stock !== undefined)
|| testgogo[a].stock - testgogo[b].stock
|| testgogo[b].sold - testgogo[a].sold )[0];
console.log(finalresult);
Thanks for any help
Javascript objects can't be ordered.
If you need that data to be in an order you should make it an array.
You could sort the entries of the object based on whether the key includes the string "newitem". Then use Object.fromEntries() to convert the sorted entries back to an object
const testgogo={newitemfgre:{brand:{gdhshd:!0},stock:2,sold:3},fruit:{brand:{grgrdgdr:!0,ggyugy:!0},stock:3,sold:2},vegetable:{brand:{htrhtr:!0},stock:1,sold:1},newitemwrewt:{brand:{gdhshd:!0},stock:2,sold:3},other:{brand:{gdhshd:!0},stock:2,sold:3},newitemncnc:{brand:{gdhshd:!0},stock:2,sold:3},snack:{brand:{htrhr:!0},stock:1,sold:4},afga:{brand:{gdhshd:!0},stock:1,sold:2},other:{brand:{gdhshd:!0},stock:2,sold:3}};
const str = "newitem";
const sortedEntries = Object.entries(testgogo)
.sort((a, b) => a[0].includes(str) - b[0].includes(str));
const output = Object.fromEntries(sortedEntries)
console.log(output)
Subtracting booleans returns a 1, -1 or 0.
true - false === 1
false - true === -1
true - true === 0
So, if a[0] has "newitem" but b[0] doesn't, the key at a[0] will be moved to the end of the entries array.
Related
I have the following array of objects:
[
{
"id" : 1,
"pricePerDay" : 50,
},
{
"id" : 2,
"pricePerDay" : 70
}
]
Based on the user input from a i want to filter either ASC or DESC on the pricePerday. Obviously this would work with:
this.products.sort((a, b) => parseFloat(b.pricePerDay) - parseFloat(a.pricePerDay));
BUT i have the variable filterType which now contains the string 'pricePerDay'. How can I use this variable to search the array of objects to properties that have the same key and sort this array based on that key?
this.products.sort((a, b) => parseFloat(b[filterType]) - parseFloat(a[filterType]));
Does this answer your question?
You can change filterType to field that you want and acs to false if you want desc order
const arr = [
{
"id" : 1,
"pricePerDay" : 50,
},
{
"id" : 2,
"pricePerDay" : 70
}
]
let filterType = 'pricePerDay'
let asc = false
const res = arr.sort((a, b) => {
if (asc) {
return parseFloat(a[filterType]) - parseFloat(b[filterType])
} else {
return parseFloat(b[filterType]) - parseFloat(a[filterType])
}
});
console.log(res)
I have an object that look like this:
{
"id": 45745049
"seller": {
"first_name": "Sam",
"last_name": "Smith",
"email": "samsmith#smith.com",
"phone": {
"number": "1111-1111",
"verified": false
},
},
"order_items": [
{
"item": {
"id": "29239765",
"title": "item1",
"colors": [
"red",
"green",
"blue"
]
},
"quantity": 1,
"unit_price": 230,
},
{
"item": {
"id": "238457363",
"title": "item2",
"colors": [
"red"
]
},
"quantity": 2,
"unit_price": 110,
}
],
"date_created": "2020-08-03T12:17:25.000-04:00",
"date_last_updated": "2020-08-03T16:51:35.61Z"
}
I want an array with pairs of EVERY key in the object with the value.
For example:
[
["id", 45745049],
["first_name", "Sam"],
.....,
["phone.number", "1111-1111"],
["phone.verified", false],
....etc
]
Everything Ok until that point. The problem is when a property is an array of objects. The output I want is the following:
[
...,
["order_items1.item.id", 29239765],
["order_items1.item.colors1", "red"],
["order_items1.item.colors2", "green"],
...,
["order_items2.item.id", 238457363],
["order_items2.item.colors1", "red"],
...etc
]
So it needs to check if the property is an array and add the position number if so.
I know I need a recursive function but I dont know how to do it.
This is what I got until now.
getObjectKeys = (obj) => {
let FieldName = "";
let FieldValue = "";
for(var prop in obj) {
FieldName += prop;
if(!(prop instanceof Array) && (typeof prop !== "object") && obj[prop]) {
FieldValue = obj[prop];
} else if(prop instanceof Array && prop.length !== 0){
prop.forEach((innerItem, i) => {
FieldName += `${i+1}.`;
// check if the inner item is an array or whatever an do it all again
// Dont know what to do here.
});
} else {
getObjectKeys(obj[prop]);
}
}
return [FieldName, FieldValue];
}
Note: I dont want the empty or null keys.
I would be very grateful if someone can help me. Thanks anyways!
This does something very similar to what you're looking for. It's a technique I use often.
const getPaths = (obj) =>
Object (obj) === obj
? Object .entries (obj) .flatMap (([k, v]) => getPaths (v) .map (p => [k, ... p]))
: [[]]
const path = (ps) => (obj) =>
ps .reduce ((o, p) => (o || {}) [p], obj)
const flatten = (obj) =>
Object .fromEntries (getPaths (obj) .map (p => [p.join('.'), path (p) (obj)]))
const input = {id: 45745049, seller: {first_name: "Sam", last_name: "Smith", email: "samsmith#smith.com", phone: {number: "1111-1111", verified: false}}, order_items: [{item: {id: "29239765", title: "item1", colors: ["red", "green", "blue"]}, quantity: 1, unit_price: 230}, {item: {id: "238457363", title: "item2", colors: ["red"]}, quantity: 2, unit_price: 110}], date_created: "2020-08-03T12: 17: 25.000-04: 00", date_last_updated: "2020-08-03T16: 51: 35.61Z"}
console .log (flatten (input))
.as-console-wrapper {min-height: 100% !important; top: 0}
The differences are that there is a separator before the array index and that I use zero-based arrays, not one-based arrays.
I would suggest that it's a much better output format. If nothing else, it would probably allow you to rehydrate the original format. But if you want to change it, you should probably simply reduce the path to combine the numeric elements with their predecessors, something like:
const flatten = (obj) =>
Object .fromEntries (getPaths (obj) .map (p => [
p .reduce (
(a, k) => /^\d+$/ .test(k) ? [...a .slice (0, -1), a [a .length - 1] + (1 + (+k))] : [...a, k],
[]
) .join ('.'),
path2 (p) (obj)
]))
But this would require changes if the outer object might be an array.
Again, though, absent a very good reason to use your requested format, I would strongly recommend my alternative.
I have an array of objects that are sorted in descending order by date:
_.sortBy
(persons.entities.alerts,
dateObj => new Date(dateObj.createdDateTime)
).reverse()
This is the array:
let persons={
"entities": {
"applicants": [
{
"lastName": "Agamemnon",
"isPrimaryApplicant": true,
"id": "16671520038"
},
{
"lastName": "Purdy",
"isPrimaryApplicant": false,
"id": "16671520039"
},
{
"lastName": "Brekky",
"isPrimaryApplicant": true,
"id": "16671520040"
},
{
"lastName": "Tabouli",
"isPrimaryApplicant": true,
"id": "16671520041"
}
],
"alerts": [
{
"createdDateTime": "2018-06-14T00:00:00.000Z",
"applicants": ["16671520038", "16671520039"],
"id": "05025fea-ec37-4767-a868-a646597365d0"
},
{
"createdDateTime": "2018-06-14T00:00:00.000Z",
"applicants": ["16671520040"],
"id": "19d0da63-dfd0-4c00-a13a-cc822fc83869"
},
{
"createdDateTime": "2018-06-14T00:00:00.000Z",
"applicants": ["16671520041"],
"id": "c5385595-2104-409d-a676-c1b57346f63e"
}
]
}
}
The sort returns the correct order by date desc. In this sample the dates are the same. Only in this case i want to sort by (applicants) lastName where isPrimaryApplicant=true? Link to codepen
You want lodash's orderBy, which allows sort directions.
You can attach asc or desc to each sort property you use.
This should get you the ordering you're looking for:
_.orderBy(persons.entities.applicants, ['lastName'], ['desc'])
Loadash sortBy doesn't provide option for comparator function(though there are other ways to achieve it)
You can use array sort method to achieve this:
persons.entities.alerts.sort(function(a1, a2) {
if(a1.createdDateTime === a2.createdDateTime) {
let applicant1 = persons.entities.applicants.find(a => a.id === a1.applicants[0]);
let applicant2 = persons.entities.applicants.find(a => a.id === a2.applicants[0]);
if (!applicant1.isPrimaryApplicant || applicant1.lastName < applicant2.lastName) {
return -1;
}
return 1;
} else {
let d1 = new Date(a1.createdDateTime);
let d2 = new Date(a2.createdDateTime);
return d2 - d1;
}
})
Would have loved to use lodash for this but the documentation does not reflect reality. The second argument to _.sortBy is an array in documentation but doesn't work if I pass an array of functions.
You can add names to your alerts and while your at it add a sortDate to use for sorting:
const persons={"entities":{"applicants":[{"lastName":"Agamemnon","isPrimaryApplicant":true,"id":"16671520038"},{"lastName":"Purdy","isPrimaryApplicant":false,"id":"16671520039"},{"lastName":"Brekky","isPrimaryApplicant":true,"id":"16671520040"},{"lastName":"Tabouli","isPrimaryApplicant":true,"id":"16671520041"}],"alerts":[{"createdDateTime":"2018-06-14T00:00:00.000Z","applicants":["16671520038","16671520039"],"id":"05025fea-ec37-4767-a868-a646597365d0"},{"createdDateTime":"2018-06-14T00:00:00.000Z","applicants":["16671520041"],"id":"19d0da63-dfd0-4c00-a13a-cc822fc83869"},{"createdDateTime":"2019-06-14T00:00:00.000Z","applicants":["16671520040"],"id":"c5385595-2104-409d-a676-c1b57346f63e"}]}}
const applicantsById = persons.entities.applicants.reduce(
(result, applicant) => result.set(applicant.id, applicant),
new Map(),
);
const alertsWithName = persons.entities.alerts.map((alert) => ({
...alert,
sortDate:new Date(alert.createdDateTime).getTime(),
name: (alert.applicants
.map((id) => applicantsById.get(id))
.filter((x) => x) //remove empty
.find((applicant)=>applicant.isPrimaryApplicant)||{lastName:''}).lastName
}));
//according to not correct lodash documentation here:
//https://lodash.com/docs/4.17.11#sortBy
//we should be able to do this:
// console.log(
// _.sortBy(alertsWithName, [
// (alert) => new Date(alert.createdDateTime),
// (alert) => alert.name,
// ])
// )
//however that's not going to work so can try array sort method
console.log(
alertsWithName.sort(
(a,b)=>b.sortDate-a.sortDate || a.name.localeCompare(b.name)
)
)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.core.js"></script>
I am trying to Sum of the key ‘total’ from the following object, but unable to find the way. I have tried to find it by using Object.key
const data = {
"item1": {},
"item2": {
"total": 13,
},
"item3": {},
"item4": {
"total": 12,
}
}
const count = Object.keys(data).map(item => data[item].total);
console.log(count);
This is what I have tried and in consol.log it is printing 13 and 12 but I am not able to do Sum of them. Also, I have tried the reduce method which is suggested in some of the following answers.
Use Object.keys() to loop over the keys of the object and then access the total property of each object:
var data = {
"item1": {
"total": 17
},
"item2": {
"total": 13
},
"item3": {}
};
var sum = 0;
Object.keys(data).forEach(key => sum += data[key].total || 0);
console.log(sum);
You can use Object.values()
The Object.values() method returns an array of a given object's own enumerable property values, in the same order as that provided by a for...in loop (the difference being that a for-in loop enumerates properties in the prototype chain as well).
and Array.prototype.reduce()
The reduce() method executes a reducer function (that you provide) on each member of the array resulting in a single output value.
const data = {
"item1": {},
"item2": {
"total": 13,
},
"item3": {},
"item4": {
"total": 12,
}
}
var sum = Object.values(data)
.filter(value => Object.keys(value).length !== 0)
.reduce((a,c) => a+c.total, 0);
console.log(sum);
Use Object.values to get all the values in your data.
Then use Array.reduce to calculate the total.
const data = {
"item1": { "total": 17 },
"item2": { "total": 13 }
}
const values = Object.values(data);
console.log("Values:", values);
const total = values.reduce((a, c) => a + c.total, 0);
console.log("Total:", total);
Of course, you don't need the intermediate variable:
const total = Object.values(data).reduce((a, c) => a + c.total, 0);
const sum = Object.keys(yourObject).map(key => yourObject[key].total).reduce((a, b) => a + b, 0);
I want to look in an array of objects if it contains a property and returns true if it found it, or false if it did not find it
An example of my array :
this.realEstateProjectMotivation.realEstateProjectOnSales[0] which is worth :
[
{
"id": 30,
"satisfied": false,
"onSaleSince":"1 day"
}
]
I would like to look in if realEstateProjectOnSales it contains onSaleSince and satisfied properties
how can I do it using Lodash or EcmaScript 2015 for example ?
You can use the in operator to check if a property exists in an object. You can loop the array with Array#some to find if at least one object contains the properties:
const arr = [
{
"id": 30,
"satisfied": false,
"onSaleSince":"1 day"
}
];
const containsProps = (item) => 'onSaleSince' in item && 'satisfied' in item;
const is0Contains = containsProps(arr[0]);
console.log('is0Contains: ', is0Contains);
const isArrayContains = arr.some(containsProps)
console.log('isArrayContains: ', isArrayContains);
It easy to do with lodash#has method:
let hasProps = _.has(arr, '[0].satisfied') && _.has(arr, '[0].onSaleSince');
const arr = [
{
"id": 30,
"satisfied": false,
"onSaleSince":"1 day"
}
];
let hasProps = _.has(arr, '[0].satisfied') && _.has(arr, '[0].onSaleSince');
console.log(hasProps);
<script src="https://cdn.jsdelivr.net/npm/lodash#4.17.4/lodash.min.js"></script>
var a = [{
id: 30,
satisfied: false,
onSaleSince: "1 day"
}, {
id: 30,
satisfied: false,
onSaleUntil: "1 day"
}];
console.log(
'Does every object in array has both `id` and `satisfied`?',
a.every(x => 'id' in x && 'satisfied' in x)
);
console.log(
'Is there any object in array which has both both `id` and `onSaleUntil`?',
a.some(x => 'id' in x && 'onSaleUntil' in x)
);
console.log(
'Does every object in array has at least one property of `onSaleSince` and `onSaleUntil`?',
a.every(x => 'onSaleSince' in x || 'onSaleUntil' in x)
);