Sorting json array - javascript

function demo() {
var test = [{
level: 19,
title: "hello1"
}, {
level: 2,
title: "hello2"
},
{
level: 5,
title: "hello5"
}];
I want to sort this array but can't find a way to do so.

You can create a custom sorting function:
// Sort by level
test.sort(function(a, b) {
return a.level - b.level;
});
Resulting object:
[
{"level":2,"title":"hello2"},
{"level":5,"title":"hello5"},
{"level":19,"title":"hello1"}
]

You can create a sort function like:
function sortBy(prop){
return function(a,b){
if( a[prop] > b[prop]){
return 1;
}else if( a[prop] < b[prop] ){
return -1;
}
return 0;
}
}
//Usage
var test = [{
level: 19,
title: "hello1"
}, {
level: 2,
title: "hello2"
},
{
level: 5,
title: "hello5"
}].sort( sortBy("level") );

Please check below code ,
<script type="text/javascript">
var test = [
{ level: 19, title: "hello1" },
{ level: 2, title: "hello2"},
{ level: 5, title: "hello5" }
];
// Before Sorting
document.write("<b>Before Sorting </b><br/>");
for (var n = 0; n < test.length; n++) {
document.write(test[n].level + ' ' + test[n].title+ '<br>');
}
// ascending order
function SortByLevel(x,y) {
return x.level - y.level;
}
function SortByTitle(x,y) {
return ((x.title == y.title) ? 0 : ((x.title> y.title) ? 1 : -1 ));
}
// Call Sort By Name
test.sort(SortByTitle);
document.write("<br/><b>After Sorting </b> <br/>");
for(var n=0;n<test.length;n++){
document.write(test[n].level + ' ' + test[n].title+ '<br>');
}
</script>

Related

Sort list of mixed alpha-numeric strings with dots?

I've got an array of objects that I need to sort using the tab property.
All the values are alphanumeric strings.
I've setup an example to show you what I have so far, which I can't seem to get working.
I need my list sorted like doc1, doc2, doc3... doc12, doc13, doc14
// Sort set of values both lexicographically and numerically
function myComparator({ tab: value1 }, { tab: value2 }) {
const _value1 = parseFloat(value1);
const _value2 = parseFloat(value2);
if (_value1 - _value2 === 0) {
return (value1 > value2) ? 1 : -1;
} else {
return _value1 - _value2;
}
}
const myArray = [
{ doc: 'Doc1', tab: '7' },
{ doc: 'Doc2', tab: '7A' },
{ doc: 'Doc3', tab: '7B' },
{ doc: 'Doc4', tab: '7.0001' },
{ doc: 'Doc5', tab: '7.01' },
{ doc: 'Doc6', tab: '7.01A' },
{ doc: 'Doc7', tab: '7.1' },
{ doc: 'Doc8', tab: '7.1A' },
{ doc: 'Doc9', tab: '7.2' },
{ doc: 'Doc10', tab: '7.3' },
{ doc: 'Doc11', tab: '7.10' },
{ doc: 'Doc12', tab: '7.11' },
{ doc: 'Doc13', tab: '7.20' },
{ doc: 'Doc14', tab: '7.34' },
];
myArray.sort(myComparator);
let html = '';
for (let i = 0; i < myArray.length; i++) {
html += '<li>' + myArray[i].doc + '</li>';
}
document.getElementById('results').innerHTML = html;
<ul id="results" />
Pulled together numerous other code snippets to find a solution. See below:
function customSort(data, key, order) {
function isNumber(v) {
return (+v).toString() === v;
}
function isRoman(s) {
// http://stackoverflow.com/a/267405/1447675
return /^M{0,4}(CM|CD|D?C{0,3})(XC|XL|L?X{0,3})(IX|IV|V?I{0,3})$/i.test(s);
}
function parseRoman(s) {
var val = { M: 1000, D: 500, C: 100, L: 50, X: 10, V: 5, I: 1 };
return s.toUpperCase().split('').reduce(function (r, a, i, aa) {
return val[a] < val[aa[i + 1]] ? r - val[a] : r + val[a];
}, 0);
}
var sort = {
asc: function (a, b) {
var i = 0,
l = Math.min(a.value.length, b.value.length);
while (i < l && a.value[i] === b.value[i]) {
i++;
}
if (i === l) {
return a.value.length - b.value.length;
}
if (isNumber(a.value[i]) && isNumber(b.value[i])) {
return a.value[i] - b.value[i];
}
if (isRoman(a.value[i]) && isRoman(b.value[i])) {
return parseRoman(a.value[i]) - parseRoman(b.value[i]);
}
return a.value[i].localeCompare(b.value[i]);
},
desc: function (a, b) {
return sort.asc(b, a);
}
};
var mapped = data.map(function (el, i) {
var string = el[key].replace(/\d(?=[a-z])|[a-z](?=\.)/gi, '$&. .'),
regex = /(\d+)|([^0-9.]+)/g,
m,
parts = [];
while ((m = regex.exec(string)) !== null) {
parts.push(m[0]);
}
return { index: i, value: parts, o: el, string: string };
});
mapped.sort(sort[order] || sort.asc);
return mapped.map(function (el) {
return data[el.index];
});
}
var arr = [
{ doc: 'Doc10', tab: '7.3' },
{ doc: 'Doc2', tab: '7B' },
{ doc: 'Doc13', tab: '7.20' },
{ doc: 'Doc0', tab: '7' },
{ doc: 'Doc1', tab: '7A' },
{ doc: 'Doc3', tab: '7C' },
{ doc: 'Doc4', tab: '7.0001' },
{ doc: 'Doc5', tab: '7.01' },
{ doc: 'Doc6', tab: '7.01A' },
{ doc: 'Doc7', tab: '7.1' },
{ doc: 'Doc8', tab: '7.1A' },
{ doc: 'Doc9', tab: '7.2' },
{ doc: 'Doc11', tab: '7.10' },
{ doc: 'Doc12', tab: '7.11' },
{ doc: 'Doc14', tab: '7.34' }
];
const myArray = customSort(arr, 'tab');
let html = '';
for (let i = 0; i < myArray.length; i++) {
html += '<li>' + myArray[i].doc + '</li>';
}
document.getElementById('results').innerHTML = html;
<ul id="results" />
The correct order I was looking for was:
7
7A
7B
7.0001
7.01
7.01A
7.1
7.1A
7.2
7.3
7.10
7.11
7.20
7.34

Traversing through JSON string to inner levels using recursive function using JavaScript

I have a JSON input which can go to any number of levels.
Here is the sample
var testJSON = [
{
'name':'USER1',
'id':1,
'child':[],
},{
'name':'USER2',
'id':2,
'child':[{
'name':'USER2_CHILD1',
'id':21,
'child':[]
},{
'name':'USER2_CHILD2',
'id':22,
'child':[{
'name':'USER2_CHILD2_CHILD1',
'id':221,
'child':[]
}]
}],
},{
'name':'USER3',
'id':3,
'child':[{
'name':'USER3_CHILD1',
'id':31,
'child':[]
}],
}];
I want to add a JSON data in child array by finding matching id using the recursive function. For example, if want to add JSON object at id==1; then it was possible by using for loop but what if I want to add JSON object at id==22 or id==221.
I am trying using below code
var body = '';
function scan(obj)
{
var k;
if (obj instanceof Object) {
for (k in obj){
if (obj.hasOwnProperty(k)){
body += 'scanning property ' + k + '<br/>';
scan( obj[k] );
}
}
} else {
body += 'found value : ' + obj + '<br/>';
};
};
scan(testJSON);
document.getElementById('output').innerHTML = body;
You could use an iteration with a check and return the object, if found.
function getObject(array, id) {
var object;
array.some(o => object = o.id === id && o || getObject(o.child || [], id));
return object;
}
var data = [{ name: "USER1", id: 1, child: [] }, { name: "USER2", id: 2, child: [{ name: "USER2_CHILD1", id: 21, child: [] }, { name: "USER2_CHILD2", id: 22, child: [{ name: "USER2_CHILD2_CHILD1", id: 221, child: [] }] }] }, { name: "USER3", id: 3, child: [{ name: "USER3_CHILD1", id: 31, child: [] }] }];
console.log(getObject(data, 1));
console.log(getObject(data, 21));
console.log(getObject(data, 221));
Try this function, you need to parse JSON before
function insertRecord(id,dataToInsert,jsonInput){
let checkIndex = function (arrayElement){
return arrayElement.id === id;
}
let index = jsonInput.findIndex(checkIndex);
if(index != -1) {
if(jsonInput[index].child) {
jsonInput[index].child.push(dataToInsert);
}
else {
jsonInput[index].child = [dataToInsert];
}
}
else {
jsonInput.forEach(function(arrEle, eleIndex){
if(arrEle.child) {
insertRecord(id,dataToInsert,arrEle.child);
}
});
}
}
insertRecord(22,{
'name':'USER1',
'id':33,
'child':[],
},testJSON);

Finding objects in a nested array along with their position

I've taken the following sample from a different question. And I am able to identify the object. But I also need to find our the position of that object. For example:
var arr = [{
Id: 1,
Categories: [{
Id: 1
},
{
Id: 2
},
]
},
{
Id: 2,
Categories: [{
Id: 100
},
{
Id: 200
},
]
}
]
If I want to find the object by the Id of the Categories, I can use the following:
var matches = [];
var needle = 100; // what to look for
arr.forEach(function(e) {
matches = matches.concat(e.Categories.filter(function(c) {
return (c.Id === needle);
}));
});
However, I also need to know the position of the object in the array. For example, if we are looking for object with Id = 100, then the above code will find the object, but how do I find that it's the second object in the main array, and the first object in the Categories array?
Thanks!
Well, if every object is unique (only in one of the categories), you can simply iterate over everything.
var arr = [{
Id: 1,
Categories: [{Id: 1},{Id: 2}]
},
{
Id: 2,
Categories: [{Id: 100},{Id: 200}]
}
];
var needle = 100;
var i = 0;
var j = 0;
arr.forEach(function(c) {
c.Categories.forEach(function(e) {
if(e.Id === needle) {
console.log("Entry is in position " + i + " of the categories and in position " + j + " in its category.");
}
j++;
});
j = 0;
i++;
});
function findInArray(needle /*object*/, haystack /*array of object*/){
let out = [];
for(let i = 0; i < haystack.lenght; i++) {
if(haystack[i].property == needle.property) {
out = {pos: i, obj: haystack[i]};
}
}
return out;
}
if you need the position and have to filter over an property of the object you can use a simple for loop. in this sample your result is an array of new object because there can be more mathches than 1 on the value of the property.
i hope it helps
Iterate over the array and set index in object where match found
var categoryGroups = [{
Id : 1,
Categories : [{
Id : 1
}, {
Id : 2
},
]
}, {
Id : 2,
Categories : [{
Id : 100
}, {
Id : 200
},
]
}
]
var filterVal = [];
var needle = 100;
for (var i = 0; i < categoryGroups.length; i++) {
var subCategory = categoryGroups[i]['Categories'];
for (var j = 0; j < subCategory.length; j++) {
if (subCategory[j]['Id'] == findId) {
filterVal.push({
catIndex : i,
subCatIndex : j,
id : needle
});
}
}
}
console.log(filterVal);
Here is solution using reduce:
var arr = [{ Id: 1, Categories: [{ Id: 1 }, { Id: 2 }, ] }, { Id: 2, Categories: [{ Id: 100 }, { Id: 200 }, ] } ]
const findPositions = (id) => arr.reduce((r,c,i) => {
let indx = c.Categories.findIndex(({Id}) => Id == id)
return indx >=0 ? {mainIndex: i, categoryIndex: indx} : r
}, {})
console.log(findPositions(100)) // {mainIndex: 1, categoryIndex: 0}
console.log(findPositions(1)) // {mainIndex: 0, categoryIndex: 0}
console.log(findPositions(200)) // {mainIndex: 1, categoryIndex: 1}
console.log(findPositions(0)) // {}
Beside the given answers with fixt depth searh, you could take an recursive approach by checking the Categories property for nested structures.
function getPath(array, target) {
var path;
array.some(({ Id, Categories = [] }) => {
var temp;
if (Id === target) {
path = [Id];
return true;
}
temp = getPath(Categories, target);
if (temp) {
path = [Id, ...temp];
return true;
}
});
return path;
}
var array = [{ Id: 1, Categories: [{ Id: 1 }, { Id: 2 },] }, { Id: 2, Categories: [{ Id: 100 }, { Id: 200 }] }];
console.log(getPath(array, 100));
.as-console-wrapper { max-height: 100% !important; top: 0; }

Check if a key value already exists in a multidimensional array object in angularjs

Suppose I have an array with object like this
array = [
{id:2,cnt:2},{id:3,cnt:3},{id:4,cnt:2},
{id:1,cnt:6},{id:2,cnt:7},{id:5,cnt:4},
{id:2,cnt:4},{id:3,cnt:2},{id:4,cnt:2},
{id:3,cnt:2},{id:4,cnt:3},{id:5,cnt:2}
];
where I need to create another array with the object where I need to add cnt value with id.
Output suppose to be like this.
output = [
{id:1,cnt:6},{id:2,cnt:13},{id:3,cnt:7},{id:4,cnt:7},{id:5,cnt:6}
];
what I have tried so far is
var general = [];
angular.forEach(array, function(value){
angular.forEach(value, function(val,key){
angular.forEach(general, function(val1,key1){
if(val1.id === val.id){
val1.cnt +=val.cnt
//#TOD0 how to add value of count and put it on general
}else{
//#TODO
general.push(val);
}
});
});
});
console.log(general);
I am unable to achieve my output. I have marked as TODO where I am confused. Can someone help me? Thanks in advance.
Array.reduce can help you a lot - you basically create a new array, and iterate your current array and check the new array to see if the current item exists. If it does, add the cnt - else add the whole item:
var mashed = arr.reduce(function(m, cur, idx) {
var found = false;
for (var i =0; i < m.length; i++) {
if (m[i].id == cur.id) {
m[i].cnt += cur.cnt;
found = true;
}
}
if (!found) {
m.push(cur)
}
return m;
}, [])
Fiddle demo: https://jsfiddle.net/1ffqv9g0/
var arr = [
{id:2,count:2,color:"red"},{id:3,count:3,color:"black"},{id:4,count:2,color:"white"},
{id:1,count:6,color:"green"},{id:2,count:7,color:"red"},{id:5,count:4,color:"blue"},
{id:2,count:4,color:"red"},{id:3,count:2,color:"black"},{id:4,count:2,color:"white"},
{id:3,count:2,color:"black"},{id:4,count:3,color:"red"},{id:5,count:2,color:"blue"}
];
var obj={};
arr.forEach(function(a){
obj[a.id]=obj[a.id]||[0];
obj[a.id][0]=obj[a.id][0]+a["count"];
obj[a.id][1]=a.color;
})
//console.log(obj);
var brr=Object.keys(obj).map(function(a){
return {"id":a,"count":obj[a][0],"color":obj[a][1]};
})
console.log(brr);
You could use a hash table for the result. For an ordered result, you could sort the result.
var array = [{ id: 2, cnt: 2 }, { id: 3, cnt: 3 }, { id: 4, cnt: 2 }, { id: 1, cnt: 6 }, { id: 2, cnt: 7 }, { id: 5, cnt: 4 }, { id: 2, cnt: 4 }, { id: 3, cnt: 2 }, { id: 4, cnt: 2 }, { id: 3, cnt: 2 }, { id: 4, cnt: 3 }, { id: 5, cnt: 2 }],
grouped = [];
array.forEach(function (a) {
if (!this[a.id]) {
this[a.id] = { id: a.id, cnt: 0 };
grouped.push(this[a.id]);
}
this[a.id].cnt += a.cnt;
}, Object.create(null));
grouped.sort(function (a, b) { return a.id - b.id; });
console.log(grouped);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Sort javascript array of objects by child properties (which may be missing)

I have a large-ish dataset (from 400 - 4,000 objects stored in an array), and I'm trying to filter them by a user-selected field.
Right now I'm using this function, found on another SO question:
var sort = function (prop, arr) {
prop = prop.split('.');
var len = prop.length;
arr.sort(function (a, b) {
var i = 0;
while( i < len ) {
a = a[prop[i]];
b = b[prop[i]];
i++;
}
if (a < b) {
return -1;
} else if (a > b) {
return 1;
} else {
return 0;
}
});
return arr;
};
Sample data - I want to sort the objects by the friends count:
var data = [
{
name: 'Jim',
friends: {
count: 20,
url: 'http://foo.com'
}
},{
name: 'Lucy',
},{
name: 'Phil',
friends: {
count: 450,
url: 'http://moo.com'
}
}
];
Notice how "Lucy" doesn't have a friends object - so when I run sort('friends.count', data);, the script breaks.
Ideally I'd like the objects which don't have the property that I'm sorting by to be put at the end of the array. Any ideas on how this can be achieved?
For example,
var data = [
{
name: 'Jim',
friends: {
count: 20,
url: 'http://foo.com'
}
},{
name: 'Lucy',
},{
name: 'Phil',
friends: {
count: 450,
url: 'http://moo.com'
}
}
];
safeGet = function(obj, prop, defaultValue) {
try {
return obj[prop]
} catch(e) {
return defaultValue
}
}
data.sort(function(x, y) {
return (
safeGet(x.friends, 'count', Infinity) -
safeGet(y.friends, 'count', Infinity));
});
document.write("<pre>" + JSON.stringify(data,0,3));
If the whole property chain (friends.count) is dynamic, change safeGet so that it iterates the list of props:
var data = [
{
name: 'Jim',
friends: {
count: 20,
url: 'http://foo.com'
}
},{
name: 'Lucy',
},{
name: 'Phil',
friends: {
count: 450,
url: 'http://moo.com'
}
}
];
safeGet = function(obj, props, defaultValue) {
try {
return props.split('.').reduce(function(obj, p) {
return obj[p];
}, obj);
} catch(e) {
return defaultValue
}
}
data.sort(function(x, y) {
return (
safeGet(x, 'friends.count', Infinity) -
safeGet(y, 'friends.count', Infinity));
});
document.write("<pre>" + JSON.stringify(data,0,3));
If you want people with no friends to go first, not last, change Infinity to -Infinity.
Your function can be modified to check for the existence of a property:
var sort = function (prop, arr) {
prop = prop.split('.');
var len = prop.length;
arr.sort(function (a, b) {
var i = 0;
var key;
while( i < len ) {
key = prop[i];
if(!a.hasOwnProperty(key)) return 1;
if(!b.hasOwnProperty(key)) return -1;
a = a[key];
b = b[key];
i++;
}
if (a < b) {
return -1;
} else if (a > b) {
return 1;
} else {
return 0;
}
});
return arr;
};
This way it will be working. I made a jsbin for the example.
#georg's answer wouldn't work with property selected dynamically.

Categories

Resources