Multidimensional sorting with underscorejs - javascript

My json structure as below;
var MyJson =
[
{
"Country": "Austria",
"SubCategory": "55",
}, {
"Country": "Brazil",
"SubCategory": "0",
}, {
"Country": "Canada",
"SubCategory": "25",
}, {
"Country": "Cyprus",
"SubCategory": "55",
}, {
"Country": "Denmark",
"SubCategory": "0",
}, {
"Country": "France",
"SubCategory": "25",
}, {
"Country": "Greece",
"SubCategory": "55",
}, {
"Country": "Hungary",
"SubCategory": "0",
}
];
I am sorting that as below;
_.sortBy(MyJson, 'SubCategory').reverse()
Result as below;
Greece : 55
Cyprus : 55
Austria : 55
France : 25
Canada : 25
Hungary : 0
Denmark : 0
Brazil : 0
My expected result as below;
Austria : 55
Cyprus : 55
Greece : 55
Canada : 25
France : 25
Brazil : 0
Denmark : 0
Hungary : 0
I have tried as below;
_.sortBy(_.sortBy(MyJson, 'SubCategory').reverse(),'Country');
is there any way to sort json as desc, asc with underscore? I am not using Lodash because of restriction of my development environment.
Thank you in advance.

Plain Javascript approach.
var data = [{ Country: "Austria", SubCategory: "55" }, { Country: "Brazil", SubCategory: "0" }, { Country: "Canada", SubCategory: "25" }, { Country: "Cyprus", SubCategory: "55" }, { Country: "Denmark", SubCategory: "0" }, { Country: "France", SubCategory: "25" }, { Country: "Greece", SubCategory: "55" }, { Country: "Hungary", SubCategory: "0" }];
data.sort(function (a, b) {
return b.SubCategory - a.SubCategory || a.Country.localeCompare(b.Country);
});
console.log(data);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Using underscore as stated: you can sort twice:
_(MyJson).chain().sortBy('Country').reverse().sortBy('SubCategory').reverse().value();
This answers is what you are looking for.
Here is stated one thing from underscore docs - sortBy is a stable algorithm.
That means you can first sort by your second property to put those in the correct order, and then sort by the first property - this will leave two fields with same value for the sorted property in the same order as found. (that order you already set with the first sort)
var MyJson =
[
{
"Country": "Austria",
"SubCategory": "55",
}, {
"Country": "Brazil",
"SubCategory": "0",
}, {
"Country": "Canada",
"SubCategory": "25",
}, {
"Country": "Cyprus",
"SubCategory": "55",
}, {
"Country": "Denmark",
"SubCategory": "0",
}, {
"Country": "France",
"SubCategory": "25",
}, {
"Country": "Greece",
"SubCategory": "55",
}, {
"Country": "Hungary",
"SubCategory": "0",
}
];
var sortedArray = _(MyJson).chain().sortBy('Country').reverse().sortBy('SubCategory').reverse().value();
console.log(sortedArray)
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore.js"></script>

Related

Javascript Grouping and Sorting

I have random cities list as below . How can I group and sort it with below criteria
SortAndGroup function should take input of the countryCode and sort accordingly with capitol city on each group at first position followed by cities in that country. Thank you for your help.
randonCities =
[
{
"name": "Delhi",
"countryCode": "IN",
"isCapitol": true
},
{
"name": "New York",
"countryCode": "USA",
"isCapitol": false
},
{
"name": "Birmingham",
"countryCode": "UK",
"isCapitol": false
},
{
"name": "London",
"countryCode": "UK",
"isCapitol": true
},
{
"name": "Hyderabad",
"countryCode": "IN",
"isCapitol": false
},
{
"name": "Chicago",
"countryCode": "USA",
"isCapitol": false
},
{
"name": "Bristol",
"countryCode": "UK",
"isCapitol": false
},
{
"name": "Washington",
"countryCode": "USA",
"isCapitol": true
}
]
End Result should be
sortByCountry(USA, UK, IND) =
[
{
"name": "Washington",
"countryCode": "USA",
"isCapitol": true
},
{
"name": "Chicago",
"countryCode": "USA",
"isCapitol": false
},
{
"name": "New York",
"countryCode": "USA",
"isCapitol": false
},
{
"name": "London",
"countryCode": "UK",
"isCapitol": true
},
{
"name": "Birmingham",
"countryCode": "UK",
"isCapitol": false
},
{
"name": "Bristol",
"countryCode": "UK",
"isCapitol": false
},
{
"name": "Delhi",
"countryCode": "IN",
"isCapitol": true
},
{
"name": "Hyderabad",
"countryCode": "IN",
"isCapitol": false
}
]
You could get the order from an array (with corresponding country names) and sort by capitol.
const
sortByCountry = (...countries) => (a, b) =>
countries.indexOf(a.countryCode) - countries.indexOf(b.countryCode) ||
b.isCapitol - a.isCapitol,
array = [{ name: "Delhi", countryCode: "IN", isCapitol: true }, { name: "New York", countryCode: "USA", isCapitol: false }, { name: "Birmingham", countryCode: "UK", isCapitol: false }, { name: "London", countryCode: "UK", isCapitol: true }, { name: "Hyderabad", countryCode: "IN", isCapitol: false }, { name: "Chicago", countryCode: "USA", isCapitol: false }, { name: "Bristol", countryCode: "UK", isCapitol: false }, { name: "Washington", countryCode: "USA", isCapitol: true }];
array.sort(sortByCountry('USA', 'UK', 'IN'));
console.log(array);
.as-console-wrapper { max-height: 100% !important; top: 0; }
ES5
var sortByCountry = function () {
var countries = Array.prototype.slice.call(arguments);
return function (a, b) {
return countries.indexOf(a.countryCode) - countries.indexOf(b.countryCode) ||
b.isCapitol - a.isCapitol;
}
},
array = [{ name: "Delhi", countryCode: "IN", isCapitol: true }, { name: "New York", countryCode: "USA", isCapitol: false }, { name: "Birmingham", countryCode: "UK", isCapitol: false }, { name: "London", countryCode: "UK", isCapitol: true }, { name: "Hyderabad", countryCode: "IN", isCapitol: false }, { name: "Chicago", countryCode: "USA", isCapitol: false }, { name: "Bristol", countryCode: "UK", isCapitol: false }, { name: "Washington", countryCode: "USA", isCapitol: true }];
array.sort(sortByCountry('USA', 'UK', 'IN'));
console.log(array);
.as-console-wrapper { max-height: 100% !important; top: 0; }
In order to sort an array, you can use:
arr.sort([compareFunction])
So you would have to write a custom compareFunction
The compareFunction compares two any elements of the array and should return 1 if the first element is "bigger" or -1 if the first element is "smaller"
arr.sort((a, b) => (a > b) ? 1 : -1)
In this case our sorting function can receive any number of parameters, so we can access them in the arguments object. We can convert the arguments object into an array and use the indexOf function to compare the position of the country code in the array.
When the country code is the same, we check if one of the items is capitol.
randomCities =
[
{
"name": "Delhi",
"countryCode": "IN",
"isCapitol": true
},
{
"name": "New York",
"countryCode": "USA",
"isCapitol": false
},
{
"name": "Birmingham",
"countryCode": "UK",
"isCapitol": false
},
{
"name": "London",
"countryCode": "UK",
"isCapitol": true
},
{
"name": "Hyderabad",
"countryCode": "IN",
"isCapitol": false
},
{
"name": "Chicago",
"countryCode": "USA",
"isCapitol": false
},
{
"name": "Bristol",
"countryCode": "UK",
"isCapitol": false
},
{
"name": "Washington",
"countryCode": "USA",
"isCapitol": true
}
]
function sortByCountry(){
var args = Array.from(arguments);
randomCities.sort( (a, b) => (args.indexOf(a.countryCode) == args.indexOf(b.countryCode)) ? (a.isCapitol ? -1 : 1) : ((args.indexOf(a.countryCode) > args.indexOf(b.countryCode)) ? 1 : -1));
return randomCities;
}
sortyByCountry('USA', 'UK', 'IN');
You could do it using Array.prototype.sort() method and sort the country code by creating an ordering array, then by capital and at last, by city name.
const sortByCountry = (data, order) =>
data.sort(
(x, y) =>
order.indexOf(x.countryCode) - order.indexOf(y.countryCode) ||
y.isCapitol - x.isCapitol ||
x.name.localeCompare(y.name)
);
const data = [
{
name: 'Delhi',
countryCode: 'IN',
isCapitol: true,
},
{
name: 'New York',
countryCode: 'USA',
isCapitol: false,
},
{
name: 'Birmingham',
countryCode: 'UK',
isCapitol: false,
},
{
name: 'London',
countryCode: 'UK',
isCapitol: true,
},
{
name: 'Hyderabad',
countryCode: 'IN',
isCapitol: false,
},
{
name: 'Chicago',
countryCode: 'USA',
isCapitol: false,
},
{
name: 'Bristol',
countryCode: 'UK',
isCapitol: false,
},
{
name: 'Washington',
countryCode: 'USA',
isCapitol: true,
},
];
const order = ['IND', 'USA', 'UK'];
console.log(sortByCountry(data, order));

Sort JSON by pre-defined set of keys in javascript

Lets suppose I have a JSON ListA:
LIST A
[
{
"address": "wellington lane",
"age": "23",
"country": "Australia",
"name": "Mike",
"profession": "Lawyer"
},
{
"address": "Street 25",
"age": "26",
"country": "New Zealand",
"name": "Parks",
"profession": "Engineer"
},
{
"address": "North cross",
"age": "29",
"country": "Korea",
"name": "Wanda",
"profession": "Doctor"
}
]
LIST B
["name","age","address","country","profession"]
The requirement is I need to sort the JSON LIST A according to the array LIST B and the output should look like:
[
{
"name": "Mike",
"age": "23",
"address": "wellington lane",
"country": "Australia",
"profession": "Lawyer"
},
{
"name": "Parks",
"age": "26",
"address": "Street 25",
"country": "New Zealand",
"profession": "Engineer"
},
{
"name": "Wanda",
"age": "29",
"address": "North cross",
"country": "Korea",
"profession": "Doctor"
}
]
How can I sort this out? I have tried this solution, but it seems this is not working.
Ciao, you could try to iterate in both arrays and create an array result with ordered attributes like this:
let input = [
{
"address": "wellington lane",
"age": "23",
"country": "Australia",
"name": "Mike",
"profession": "Lawyer"
},
{
"address": "Street 25",
"age": "26",
"country": "New Zealand",
"name": "Parks",
"profession": "Engineer"
},
{
"address": "North cross",
"age": "29",
"country": "Korea",
"name": "Wanda",
"profession": "Doctor"
}
]
let fields = ["name","age","address","country","profession"]
let result = [];
input.forEach(el => {
let resultobj = {}
fields.forEach(fi => {
resultobj[fi] = el[fi]
})
result.push(resultobj)
})
console.log(result)
Here's a solution using map and reduce:
const arr = [
{
"address": "wellington lane",
"age": "23",
"country": "Australia",
"name": "Mike",
"profession": "Lawyer"
},
{
"address": "Street 25",
"age": "26",
"country": "New Zealand",
"name": "Parks",
"profession": "Engineer"
},
{
"address": "North cross",
"age": "29",
"country": "Korea",
"name": "Wanda",
"profession": "Doctor"
}
];
const order = ["name", "age", "address", "country", "profession"];
const newArr = arr.map(e => order.reduce((obj, key) => ({ ...obj, [key]: e[key] }), {}));
console.log(newArr);
One way to do this without having to rely on an external library:
const arr = [
{
'address': 'wellington lane',
'age': '23',
'country': 'Australia',
'name': 'Mike',
'profession': 'Lawyer',
},
{
'address': 'Street 25',
'age': '26',
'country': 'New Zealand',
'name': 'Parks',
'profession': 'Engineer',
},
{
'address': 'North cross',
'age': '29',
'country': 'Korea',
'name': 'Wanda',
'profession': 'Doctor',
},
];
const keyOrder = ['name', 'age', 'address', 'country', 'profession'];
function applyKeyOrder(obj, keyOrder) {
const res = {};
for (const key of keyOrder) {
res[key] = obj[key];
}
return res;
}
const result = arr.map(element => applyKeyOrder(element, keyOrder));
console.log(result);
Note that this assumes that all keys in the keyOrder-array actually exist in the objects, i.e. fields would get lost if they're not present in the array.
Where "LIST A" is listA and "LIST B" is listB:
const formatList = () => {
return listA.map(item => {
const res = {};
listB.map(label => {
res[label] = item[label];
})
return res;
})
};
console.log(formatList())

Django REST - JSON API results as list by key

I have a very basic API made with Django Rest Framework with an output as follows:
[
{
"name": "John",
"city": "chicago",
"age": "22"
},
{
"name": "Gary",
"city": "florida",
"age": "35"
},
{
"name": "Selena",
"city": "vegas",
"age": "18"
}
]
I want to convert it to the following format to simplify the usage of its data in charts.
{
"name": ["John", "Gary", "Selena"]
"city": ["chicago", "vegas", "florida"]
"age": ["22", "35", "18"]
}
Is there a simple way this can be done in Javascript (and Python just for curiosity)?
2. Can this be proactively solved by adjusting the Serializer or the ViewSet in DRF?
Javascript version:
const data = [
{
name: 'John',
city: 'chicago',
age: '22',
},
{
name: 'Gary',
city: 'florida',
age: '35',
},
{
name: 'Selena',
city: 'vegas',
age: '18',
},
];
const result = Object.keys(data[0]).reduce((obj, key) => {
obj[key] = data.map(_ => _[key]);
return obj;
}, {});
console.log(result);
In Python you could do it like this:
data = [
{
"name": "John",
"city": "chicago",
"age": "22"
},
{
"name": "Gary",
"city": "florida",
"age": "35"
},
{
"name": "Selena",
"city": "vegas",
"age": "18"
}
]
result = {}
for key in data[0]:
result[key] = []
for entry in data:
for key in entry:
result[key].append(entry[key])
print(result)
check this
data = [
{
"name": "John",
"city": "chicago",
"age": "22"
},
{
"name": "Gary",
"city": "florida",
"age": "35"
},
{
"name": "Selena",
"city": "vegas",
"age": "18"
}
]
output = []
name = []
city = []
age = []
for i in data:
name.append(i['name'])
city.append(i['city'])
age.append(i['age'])
output.append({"name":name,"city":city,"age":age})
print(output)

Merging parts of JSON objects in an array

Is there an easy way in javascript (running on nodejs) to merge various attributes of an object in an array? I know I can do it using some for loops etc, but was wondering if there is any easier way. My array of objects is like this -
[
{
"asin": "123456",
"isbn": "09876543",
"title": "Joe bloggs",
"country": "us",
"published_date": "2019-07-30",
"AmazonProductPageInfo": {
"id": 1108,
"title_asin": "123456",
"country": "us",
"date_of_extraction": "2020-07-04"
},
"AmazonCategoryRank": {
"category_name": "Tom",
"category_rank": 78,
"date_of_extraction": "2020-07-04"
}
},
{
"asin": "123456",
"isbn": "09876543",
"title": "Joe bloggs",
"country": "us",
"published_date": "2019-07-30",
"AmazonProductPageInfo": {
"id": 1108,
"title_asin": "123456",
"country": "us",
"date_of_extraction": "2020-07-04"
},
"AmazonCategoryRank": {
"category_name": "Dick",
"category_rank": 103,
"date_of_extraction": "2020-07-04"
}
},
{
"asin": "123456",
"isbn": "09876543",
"title": "Joe bloggs",
"country": "us",
"published_date": "2019-07-30",
"AmazonProductPageInfo": {
"id": 1108,
"title_asin": "123456",
"country": "us",
"date_of_extraction": "2020-07-04"
},
"AmazonCategoryRank": {
"category_name": "Harry",
"category_rank": 267,
"date_of_extraction": "2020-07-04"
}
},
{
"asin": "123456",
"isbn": "09876543",
"title": "Joe bloggs",
"country": "us",
"published_date": "2019-07-30",
"AmazonProductPageInfo": {
"id": 1108,
"title_asin": "123456",
"country": "us",
"date_of_extraction": "2020-04-20"
},
"AmazonCategoryRank": {
"category_name": "Tom",
"category_rank": 42,
"date_of_extraction": "2020-04-20"
}
},
{
"asin": "123456",
"isbn": "09876543",
"title": "Joe bloggs",
"country": "us",
"published_date": "2019-07-30",
"AmazonProductPageInfo": {
"id": 1108,
"title_asin": "123456",
"country": "us",
"date_of_extraction": "2020-04-20"
},
"AmazonCategoryRank": {
"category_name": "Dick",
"category_rank": 60,
"date_of_extraction": "2020-04-20"
}
},
{
"asin": "123456",
"isbn": "09876543",
"title": "Joe bloggs",
"country": "us",
"published_date": "2019-07-30",
"AmazonProductPageInfo": {
"id": 1108,
"title_asin": "123456",
"country": "us",
"date_of_extraction": "2020-04-20"
},
"AmazonCategoryRank": {
"category_name": "Harry",
"category_rank": 132,
"date_of_extraction": "2020-04-20"
}
}
]
And I would like them to be merged like this based on date_of_extraction
[
{
"asin": "123456",
"isbn": "09876543",
"title": "Joe bloggs",
"country": "us",
"published_date": "2019-07-30",
"AmazonProductPageInfo": {
"id": 1108,
"title_asin": "123456",
"country": "us",
"date_of_extraction": "2020-07-04"
},
"AmazonCategoryRank":[
{
"category_name": "Tom",
"category_rank": 78,
"date_of_extraction": "2020-07-04"
},
{
"category_name": "Dick",
"category_rank": 103,
"date_of_extraction": "2020-07-04"
},
{
"category_name": "Harry",
"category_rank": 267,
"date_of_extraction": "2020-07-04"
}
]
},
{
"asin": "123456",
"isbn": "09876543",
"title": "Joe bloggs",
"country": "us",
"published_date": "2019-07-30",
"AmazonProductPageInfo": {
"id": 1108,
"title_asin": "123456",
"country": "us",
"date_of_extraction": "2020-04-20"
},
"AmazonCategoryRank": [
{
"category_name": "Tom",
"category_rank": 42,
"date_of_extraction": "2020-04-20"
},
{
"category_name": "Dick",
"category_rank": 60,
"date_of_extraction": "2020-04-20"
},
{
"category_name": "Harry",
"category_rank": 132,
"date_of_extraction": "2020-04-20"
}
]
}
]
There is a good npm package called deepmerge looking at it might solve your problem.
You can do this in code via loops or just with functions such as Array.prototype.reduce in code of course.
If you're looking for a totally different way, databases are also quite good at grouping data. I'm doing something similar using mongodb-memory-server where I am making a temporary collection then streaming a large set of raw data into it and then using mongo aggregate pipelines to do the transformation work.
In this case for you, assuming you stream your sample records into a collection, your query may look something like this:
db.test.aggregate([
{
$group: {
_id: "$AmazonProductPageInfo.date_of_extraction",
asin: { $first: "$asin" },
isbn: { $first: "$isbn" },
title: { $first: "$title" },
country: { $first: "$country" },
published_date: { $first: "$published_date" },
AmazonProductPageInfo: { $first: "$AmazonProductPageInfo" },
AmazonCategoryRank: { $push: "$AmazonCategoryRank" }, // $push here
}
}
])
Where you use $first to pick the first scalar value for each field of the group, assuming they are all the same and use $push for the category rank objects which are distinct per group. That should give you your desired results.
You can then use a cursor to iterate over them all or do further transformations or aggregations in the same pipeline.

Get data from JSON object using value within

My JSON is as follows:
{
"sales": [{
"manager": "alberic",
"surgeon": "Dr Barry Biggins",
"amount": "300",
"country": "USA",
"percent-seller": "30",
"antiquity": "June 2017",
"date": "6"
}, {
"manager": "support",
"surgeon": "Dr Barry Biggins",
"amount": "300",
"country": "UK",
"percent-seller": "20",
"antiquity": "June 2017",
"date": "2"
}, {
...
}]
}
I want to retrieve the objects from sales where manager = "support" and date = "2". How do I go about this in jQuery?
Thanks!
Simply you can use filter() method and use your condition inside filter method function will return element if your condition become true otherwise it ignore element.
data= {"sales": [{
"manager": "alberic",
"surgeon": "Dr Barry Biggins",
"amount": "300",
"country": "USA",
"percent-seller": "30",
"antiquity": "June 2017",
"date": "6"
}, {
"manager": "support",
"surgeon": "Dr Barry Biggins",
"amount": "300",
"country": "UK",
"percent-seller": "20",
"antiquity": "June 2017",
"date": "2"
},
]
};
var matchedElements = data.sales.filter(function(element) {
return (element.manager == 'support' && element.date == '2');
});
console.log(matchedElements);
//if you want to access surgeon of first element of matchedElements
console.log(matchedElements[0].surgeon);
//if you want to access surgeon of all elements in matchedElements
for(i in matchedElements)
{
console.log(matchedElements[i].surgeon);
}
You filter the sales array.
Make sure to add the polyfill from the above link if you want to support older browsers.
var matchingSales = jsonData.sales.filter(function(sale) {
return sale.manager == 'support' && sale.date == '2';
});
var data = {
"sales": [{
"manager": "alberic",
"surgeon": "Dr Barry Biggins",
"amount": "300",
"country": "USA",
"percent-seller": "30",
"antiquity": "June 2017",
"date": "6"
}, {
"manager": "support",
"surgeon": "Dr Barry Biggins",
"amount": "300",
"country": "UK",
"percent-seller": "20",
"antiquity": "June 2017",
"date": "2"
}]
};
$.each(data.sales, function(i, v) {
if (v.manager == 'support' && v.date == '2') {
console.log(v.manager)
console.log(v.surgeon)
console.log(v.amount)
}
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Iterate over them using .each()

Categories