I have an array like this and I wnat to ignore first two object and then sort the based on its ISD code in ascdeing order.
My data
"Output" :
[{
Name:"Country"
},{
Name :"CODE"
},
{
"Name" : "Alex",
"Country" :"India",
"CODE": "91"
},{
"Name" : "David",
"Country" : "USA",
"CODE": "1"
},{
"Name" :"Ravi",
"Country" : "NZ"
"CODE": "61"
},{
"Name" :"Smith",
"Country" : "AUS"
"CODE": "64"
}
]
What I am trying here is
var sortedData = sortByKey(output,"CODE")
function sortByKey(array, key) {
return array.sort(function(a, b) {
var x = a[key]; var y = b[key];
return ((x < y) ? -1 : ((x > y) ? 1 : 0));
});
}
But it is rearranging the data rendomly. CAn anyone help me what is going wrong here.
You coudld take localeCompare with some options for sorting numerical values in the right order.
function sortByKey(array, key) {
var temp = array.slice(2);
temp.sort(function (a, b) {
return (a[key] || '').localeCompare(b[key] || '', undefined, { numeric: true, sensitivity: 'base' });
});
return array.slice(0, 2).concat(temp);
}
var array = [{ Name: "Country" }, { Name: "CODE" }, { Name: "Alex", Country: "India", CODE: "2" }, { Name: "David", Country: "USA", CODE: "1" }, { Name: "Ravi", Country: "NZ", CODE: "11" }, { Name: "Smith", Country: "AUS", CODE: "24" }];
console.log(sortByKey(array, "CODE"));
.as-console-wrapper { max-height: 100% !important; top: 0; }
This is working perfectly. If you are looking for numeric sort use parseFloat
If you don't need the data with CODE key use below method
`
var JSON = {
"Output": [
{Name: "Country"},
{Name: "CODE"},
{"Name": "Alex","Country": "India","CODE": "91"},
{"Name": "David","Country": "USA","CODE": "1"},
{"Name": "Ravi","Country": "NZ","CODE": "61"},
{"Name": "Smith","Country": "AUS","CODE": "64"}]
}
var sortedJSON = sortByKey(JSON.Output, "CODE");
console.log(sortedJSON);
function sortByKey(array, key) {
for (var obj in array) {
if(array[obj][key] === undefined) {
delete array[obj];
}
}
return array.sort(function (a, b) {
if(a[key] && b[key]){
var x = parseInt(a[key]);
var y = parseInt(b[key]);
return ((x < y) ? -1 : ((x > y) ? 1 : 0));
}
});
}
If you want to keep the objects without code use the one below
var JSON = {
"Output": [
{Name: "Country"},
{Name: "CODE"},
{"Name": "Alex","Country": "India","CODE": "91"},
{"Name": "David","Country": "USA","CODE": "1"},
{"Name": "Ravi","Country": "NZ","CODE": "61"},
{"Name": "Smith","Country": "AUS","CODE": "64"}]
}
var sortedJSON = sortByKey(JSON.Output, "CODE");
console.log(sortedJSON);
function sortByKey(array, key) {
return array.sort(function (a, b) {
if(a[key] && b[key]){
var x = parseInt(a[key]);
var y = parseInt(b[key]);
return ((x < y) ? -1 : ((x > y) ? 1 : 0));
}
});
}
This should works, hope it helps!
var data = [
{ "Name": "Country" },
{ "Name": "CODE" },
{ "Name": "Alex", "Country": "India", "CODE": "91" },
{ "Name": "David", "Country": "USA", "CODE": "1" },
{ "Name": "Ravi", "Country": "NZ", "CODE": "61" },
{ "Name": "Smith", "Country": "AUS", "CODE": "64" }
];
var sortedJSON = sortByKey(data, "CODE");
function sortByKey(array, key) {
var others = [], result;
result = array.filter(function(o) {
if (!o[key]) others.push(o);
return (o[key]);
}).sort(function(a, b) {
var x = a[key], y = b[key];
return ((x < y) ? -1 : ((x > y) ? 1 : 0));
});
return others.concat(result);
}
console.log(sortedJSON);
Related
I have the following JavaScript object. I need to generate a new object from the given object. What is the approach I should take in JavaScript?
[
{"name": "Dan", "city" : "Columbus", "ZIP":"47201"},
{"name": "Jen", "city" : "Columbus", "ZIP":"47201"},
{"name": "Mark", "city" : "Tampa", "ZIP":"33602"},
]
How can I transform or pivot to generate the following object?
[
{ "47201": [
{"name": "Dan", "city": "Columbus"},
{"name": "Jen", "city": "Columbus"},
],
"count": "2"
},
{ "33602": [
{"name": "Mark", "city": "Tampa"}
],
"count": "1"
}
]
I don't know why you want the .count property, when that can be accessed via the array's .length property, but anyway:
const input = [
{"name": "Dan", "city" : "Columbus", "ZIP":"47201"},
{"name": "Jen", "city" : "Columbus", "ZIP":"47201"},
{"name": "Mark", "city" : "Tampa", "ZIP":"33602"},
]
const working = input.reduce((acc, {ZIP, name, city}) => {
(acc[ZIP] || (acc[ZIP] = [])).push({name, city})
return acc
}, {})
const output = Object.keys(working)
.map(k => ({[k]: working[k], count: working[k].length}))
console.log(output)
Further reading:
Array .reduce()
Array .map()
Object.keys()
Unpacking fields from objects passed as function parameters
Computed property names
The below code will work for your requirement. The final result is stored in the variable result which holds the array object.
var source = [{
"name": "Dan",
"city": "Columbus",
"ZIP": "47201"
},
{
"name": "Mark",
"city": "Tampa",
"ZIP": "33602"
},
{
"name": "Jen",
"city": "Columbus",
"ZIP": "47201"
}
];
var result = [];
finalarr('ZIP');
function finalarr(propname) {
var obj = JSON.parse(JSON.stringify(source));
obj.forEach(function(elm,i) {
var arr = {};var chli=[];var charr={};
var flag = 0;
for (var prop in elm) {
if(prop != propname){
charr[prop]=elm[prop];
}
}
for(var i=0;i<result.length;i++){
if(result[i][elm[propname]]){
result[0][elm[propname]].push(charr);
//console.log(result[i][propname]);
flag = 1;
}
}
if(flag == 0){
chli.push(charr);
arr["count"] = checkarr(obj,propname,elm[propname]);
arr[elm[propname]]=chli;
result.push(arr);
}
});
}
function checkarr(obj,propname,value){
var count = 0;
obj.forEach(function(elm,i) {
if(elm[propname] == value){
count++;
}
});
return count;
}
console.log(result);
i'm searching a smart way to reoganise an array by a element inside it:
In entry i've got:
[{"name": "brevet",
"country": "fr"
},{
"name": "bac",
"country": "fr"
},{
"name": "des",
"country": "ca"
},{
"name": "dep",
"country": "ca"
}{
"name": "other",,
"country": "other"}]
I want to reorganize my array by country to have this in my output:
[{
"name": "fr",
"degrees": [
{
"name": "brevet",
"country": "fr"
},{
"name": "bac",
"country": "fr"
}]
},{
"name": "ca",
"degrees": [{
"name": "des",
"country": "ca"
},{
"name": "dep",
"country": "ca"
}]
},{
"name": "other",
"degrees": [{
"name": "other",
"country": "other"
}]
}]
For this i write a dirty function, but it seems to me there is a better way but i don't see how. If someone can ligth my brain in a better way to do this i'll be helpfull
private organizeDegrees(degrees: Array<SubscriptionFieldInterface>) {
let degreesByCountry = new Array();
let storeIndex = new Array();
degrees.map(degree => {
let index = null;
storeIndex.find((element, idx) => {
if (element === degree.country) {
index = idx;
return true;
}
});
if (index === null) {
index = degreesByCountry.length;
let newEntry = {
'name': degree.country,
'degrees': new Array()
};
storeIndex.push(degree.country);
degreesByCountry.push(newEntry);
}
degreesByCountry[index].degrees.push(degree);
});
return degreesByCountry;
}
thank's
You can group the array and map the object using Object.keys:
var groupBy = function(xs, key) {
return xs.reduce(function(rv, x) {
(rv[x[key]] = rv[x[key]] || []).push(x);
return rv;
}, {});
};
var grouped = groupBy(array, "country");
var mappedArray = Object.keys(grouped).map(key => ( {name: key, degrees: grouped [key]} ));
And one more way:
arr = [ /* your array */ ];
arr = Object.values(arr.reduce((ac, el) => {
if(!ac[el.country]) ac[el.country] = {"name": el.country, "degrees": []}
ac[el.country].degrees.push(el);
return ac
}, {}))
console.log(arr) // formated
Another solution, which also handles 'id' => '#id' mapping:
const a = [{"name":"brevet","country":"fr"},{"name":"bac","country":"fr"},{"id":73,"name":"des","country":"ca"},{"name":"dep","country":"ca"},{"name":"other","country":"other"}];
const r = [...new Set(a.map(({country}) => country))] // list of unique country names
.map(c => Object.assign({name: c}, // for each country
{degrees: a.filter(x => x.country === c).map(y => Object.keys(y).includes('id') // handle 'id' => '#id' mutation
? {'#id': "/subscription_fields/" + y.id, name: y.name, country: y.country}
: y)
}))
console.log(r)
This is purely ES6, and quite terse, but possibly less readable. Also, it doesn't add the "#id": "/subscription_fields/83", which could be added as a post process:
const groupByKey = (arr, key) => [...arr.reduce((acc, deg) =>
acc.set(deg[key], {name: deg[key], degrees: [ ...(acc.get(deg[key]) || {degrees: []}).degrees, deg]})
, new Map()).values()];
console.log(groupByKey(degrees, 'country'));
You could use a hash table and collect all values in an object. For getting the result array, you need to push the object only once.
var data = [{ name: "brevet", country: "fr" }, { name: "bac", country: "fr" }, { id: 73, name: "des", country: "ca" }, { name: "dep", country: "ca" }, { name: "other", country: "other" }],
result = data.reduce(function (hash) {
return function (r, a) {
if (!hash[a.country]) {
hash[a.country] = { name: a.country, degrees: [] };
r.push(hash[a.country]);
}
hash[a.country].degrees.push({ name: a.name, country: a.country });
return r;
};
}(Object.create(null)), []);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Example of the object data I am dealing with
var myData = [{
"name": "John",
"age": 30,
"interest": "Baseball"
},
{
"name": "Bob",
"age": 21,
"interest": "Baseball"
},
{
"name" : "Sally",
"age" : 29,
"interest": "Tennis"
}]
I am trying to figure out the easiest way to group them by interests. I am open to using lodash or underscore, but I cannot get the final result to look like this....
I want this to be the output:
[{ "Baseball" : [{
"name": "John",
"age" : 30
},
{
"name" : "Bob",
"age" : 21
}]
},
{ "Tennis" : [{
"name" : "Sally",
"age" : 21
}]
}];
Basically, each interest becomes a new object key containing all of the matched values within arrays.
I am having trouble constructing this output. Any assistance would be greatly appreciated. I prefer to use lodash/underscore to keep things very easy.
Thank you!
You could use Array.reduce for this:
var myData = [
{
"name": "John",
"age": 30,
"interest": "Baseball"
},
{
"name": "Bob",
"age": 21,
"interest": "Baseball"
},
{
"name" : "Sally",
"age" : 29,
"interest": "Tennis"
}];
var result = myData.reduce(function(entities, obj) {
entities[obj.interest] = (entities[obj.interest] || []).concat({
name: obj.name,
age: obj.age
});
return entities;
}, {});
console.log(result);
A little bit more general approach:
function groupBy(data, key, tFunc) {
mapFunc = (typeof tFunc === "function")? tFunc: function(o) { return o };
return (Array.isArray(data)?data:[]).reduce(function(entities, o) {
if(o[key]) {
entities[o[key]] = (entities[o[key]] || []).concat(tFunc(o));
}
return entities;
}, {});
}
// test code
var myData = [
{
"name": "John",
"age": 30,
"interest": "Baseball"
},
{
"name": "Bob",
"age": 21,
"interest": "Baseball"
},
{
"name" : "Sally",
"age" : 29,
"interest": "Tennis"
}];
var result = groupBy(myData, "interest", function(o) { return { name: o.name, age: o.age}});
console.log(result);
var result2 = groupBy(myData, "age", function(o) { return o.name});
console.log(result2);
A group-by operation can be done by matching values in a dictionary (hashtable). In JavaScript all objects are dictionaries with property-names as the keys, for values we use arrays.
For example (press the "Run code snippet" button below to see the results):
function groupBy( input, propertyName ) {
var output = {};
for(var i = 0; i < input.length; i++) {
var groupByValue = input[i][propertyName];
if( !(groupByValue in output) ) {
output[ groupByValue ] = [];
}
var dolly = cloneObjectButIgnoreProperty( input[i], propertyName );
output[ groupByValue ].push( dolly );
}
return output;
}
function cloneObjectButIgnoreProperty( value, ignorePropertyName ) {
var dolly = {};
var propertyNames = Object.keys( value );
for( var i = 0; i < propertyNames .length; i++ ) {
var propertyName = propertyNames[i];
if( propertyName == ignorePropertyName ) continue;
dolly[propertyName ] = value[propertyName ];
}
return dolly;
}
var myData = [
{
"name": "John",
"age": 30,
"interest": "Baseball"
},
{
"name": "Bob",
"age": 21,
"interest": "Baseball"
},
{
"name" : "Sally",
"age" : 29,
"interest": "Tennis"
}
];
var groupedByInterest = groupBy( myData, 'interest' );
console.log( "By interest:" );
console.log( groupedByInterest );
var groupedByName = groupBy( myData, 'name' );
console.log( "By name:" );
console.log( groupedByName );
var groupedByAge = groupBy( myData, 'age' );
console.log( "By age:" );
console.log( groupedByAge );
The solution using Array.prototype.reduce() function:
var myData = [{ "name": "John", "age": 30, "interest": "Baseball" }, { "name": "Bob", "age": 21, "interest": "Baseball" }, { "name" : "Sally", "age" : 29, "interest": "Tennis" }],
result = myData.reduce(function (r, o) {
r[o.interest] = r[o.interest] || [];
r[o.interest].push({name: o.name, age: o.age});
return r;
}, {});
console.log(result);
var myData = [{name:"John",age:30,interest:"Baseball"},{name:"Bob",age:21,interest:"Baseball"},{name:"Sally",age:29,interest:"Tennis"}],
result = [],
interests = [...new Set(myData.map(v => v.interest))];
interests.forEach(v => result.push({ [v] : [] }));
myData.forEach((v,i) => result.forEach((c,i) => Object.keys(c)[0] == v.interest ? result[i][v.interest].push({name: v.name, age: v.age}) : c))
console.log(result);
I want to load an external JSON object and sort based on one or more key:value pairs.
For example using the JSON below I might need to sort on category1 and then type.
I've tried array.sort() but no matter what I throw at it my data is never sorted; It's always output in the same order as in the JSON file.
{
"books": [
{
"sku": "{1234}",
"title": "Moby Dick",
"type": "paperback",
"category1": "fiction",
"category2": "classic",
"category3": "",
"image": "",
"ctaLabel": "Learn More"
},
{
"sku": "{5678}",
"title": "1984",
"type": "hardcover",
"category1": "fiction",
"category2": "",
"category3": "",
"image": "",
"ctaLabel": "Learn More"
},
{
"sku": "{5678}",
"title": "Another Title",
"type": "paperback",
"category1": "nonfiction",
"category2": "youngadult",
"category3": "",
"image": "",
"ctaLabel": "Learn More"
}
]
}
$(function() {
$.getJSON('books.json', function (data) {
console.log(data);
var items = data.books.map(function (item) {
return item.sku + ': ' + item.title;
});
if (items.length) {
var content = '<li>' + items.join('</li><li>') + '</li>';
var list = $('<ul />').html(content);
$("#show-data").html(list);
}
});
});
Based on this answer, you can implement a multi-level sort as follows :
function multiLevelSort(arr, criteria) {
return arr.sort(function(x, y) {
return criteria.reduce(function(prev, curr) {
var dir = (curr.dir < 0) ? -1 : 1,
x_ = x[curr.prop],
y_ = y[curr.prop];
return prev || (x_ === y_ ? 0 : x_ > y_ ? dir : -dir);
}, 0);
});
}
or, with destructuring (in Node but not yet in all browsers) :
function multiLevelSort(arr, criteria) {
return arr.sort(function(x, y) {
return criteria.reduce(function(prev, {prop, dir}) {
dir = (dir < 0) ? -1 : 1;
var x_ = x[prop],
y_ = y[prop];
return prev || (x_ === y_ ? 0 : x_ > y_ ? dir : -dir);
}, 0);
});
}
where :
arr is an array of objects, as in the question.
criteria is an array of objects of the following format :
var criteria = [
{prop: "type", dir: 1}, // dir:1=ascending; dir:-1=descending
{prop: "category1", dir: 1},
{prop: "category2", dir: 1}
];
Then simply call :
multiLevelSort(myArray, myCriteria);
Like Array.prototype.sort(), myArray will be mutated and returned.
DEMO
I have this JSON structure:
[{
"name": "ankit",
"DOB": "23/06"
}, {
"name": "kapil",
"DOB": "26/06"
}, {
"name": "ankit",
"DOB": "27/06"
}]
I want to count similar object with value ankit. How can I do this?
You can use Array.prototype.filter():
var count = json.filter(function (el) {
return el.name == 'ankit';
}).length;
How about:
let a = [
{ "name": "ankit", "DOB": "23/06" },
{ "name": "kapil", "DOB": "26/06" },
{ "name": "ankit", "DOB": "27/06" }
];
let count = 0;
a.forEach(item => {
if (item.name === "ankit") {
count++;
}
});
(code in playground)
You could use an object for counting and get the wanted count for a name with the name as property.
var data = [{ "name": "ankit", "DOB": "23/06" }, { "name": "kapil", "DOB": "26/06" }, { "name": "ankit", "DOB": "27/06" }],
count = {};
data.forEach(function (a) {
count[a.name] = (count[a.name] || 0) + 1;
});
console.log(count);
console.log(count['ankit']);
You can use the reduce method to reduce the items that have the name ankit to a number.
var items = [
{
name: 'ankit',
DOB: '23/06'
},
{
name: 'kapil',
DOB: '26/06'
},
{
name: 'ankit',
DOB: '27/06'
}
]
var numItems = items.reduce(function (count, item) {
return item.name === 'ankit' ? count + 1 : count
}, 0)
document.write('Number of items with the name `ankit`: ' + numItems)
1. Get the object from JSON:
var obj = JSON.parse(text);
2. Get your array filtered:
var count = obj.filter(function(obj) { return obj.name == "ankit" }).length;