Underscore multidimensional sortBy - javascript

I have an object.
[
{ "home1": { "mesafe":11 } },
{ "home2": { "mesafe": 6 } },
{ "home3": { "mesafe":42 } },
{ "home4": { "mesafe":23 } },
{ "home5": { "mesafe": 5 } }
]
How can I sort this object with mesafe field order by ASC numeric using underscore ?

You can consider
{
"home1": {
"mesafe":11
}
}
as
{
"home1": {
"mesafe":11
},
// fakes
"home2": {},
"home3": {}...
}
Now the value to sort can be described to :
Get all mesafe attribute's value from subObject and sum them up (if the attribute exist).
So you can use _.reduce to achieve it.
var list = [
{ "home1": { "mesafe":11 } },
{ "home2": { "mesafe": 6 } },
{ "home3": { "mesafe":42 } },
{ "home4": { "mesafe":23 } },
{ "home5": { "mesafe": 5 } }
];
var sortedList = _.sortBy(list, function(item) {
// For each item, we acts as there not only have one attribute "homex", but there's many other like "homey : {}".
var res = _.reduce(item, function(res, sub) {
// So we can the again use reduce to iterate through them, and add the value if mesafe exist.
return (sub.mesafe == null) ? res : res + sub.mesafe;
}, 0);
return res;
});
console.log(sortedList);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script>

You can use JavaScript Array sort() Method to sort the array based on value in mesafe field.
var data = [
{ "home1": { "mesafe":11 } },
{ "home2": { "mesafe": 6 } },
{ "home3": { "mesafe":42 } },
{ "home4": { "mesafe":23 } },
{ "home5": { "mesafe": 5 } }
];
// get the value from mesafe field
function getMesafeValue(a) {
for (var key in a) {
if (a.hasOwnProperty(key)) {
return a[key].mesafe;
}
}
}
// sort the array
data.sort(function(a, b) {
var v1 = getMesafeValue(a);
var v2 = getMesafeValue(b);
return v1 < v2 ? -1 : (v1 > v2 ? 1 : 0);
});
// print the array after sorting
for (var i = 0; i < data.length; i++) {
for (var key in data[i]) {
if (data[i].hasOwnProperty(key)) {
document.write(key + " -> " + data[i][key].mesafe + '<br/>');
}
}
}

Related

try to filter the records from the array of objects

I have the array of objects and i am trying to show the records based upon some filtration,
I am doing in VUE
Here is my code
return this.system.filter(function (item, key) {
if(key.)
});
what i am tryin to achieve , if the key is: 1,2,3,4,5 it should be equal to 9 and display A because 9 is equal to A
because my keys are like this
this.system = [
{
key:0,"value:"x"
},
{
key:1,"value:"x1"
},
{
key:2,"value:"x2"
},
{
key:3,"value:"x3"
},
{
key:4,"value:"x4"
},
{
key:5,"value:"x5"
},
{
key:6,"value:"x6"
},
{
key:7,"value:"x7"
},
{
key:8,"value:"x8"
},
{
key:9,"value:"A"
},
{
key:10,"value:"B"
},
{
key:11,"value:"C"
},
{
key:12,"value:"D"
},
]
If I understood you correctly :
new Vue({
el: '#demo',
data() {
return {
system: [{key:0,value:"x"}, {key:1,value:"x1"}, {key:2,value:"x2" }, {key:3,value:"x3"}, {key:4,value:"x4"}, {key:5,value:"x5"}, {key:6,value:"x6"}, {key:7,value:"x7"}, {key:8,value:"x8"}, {key:9,value:"A"}, {key:10,value:"B"}, {key:11,value:"C"}, {key:12,value:"D"},],
chose: 0,
}
},
computed: {
result() {
return this.system.filter(item => {
if (+this.chose > 0 && +this.chose < 6 || +this.chose === 9) {
return item.key === 9
} else {
return item.key === +this.chose
}
})
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="demo">
<input v-model="chose" type="number" />
{{ result }}
</div>
As per my understanding, You want to return value of value property based on the value of key property. If Yes, You can simply achieve that by using Array.find() method. Here you go :
const system = [
{
key:0,value:"x"
},
{
key:1,value:"x1"
},
{
key:2,value:"x2"
},
{
key:3,value:"x3"
},
{
key:4,value:"x4"
},
{
key:5,value:"x5"
},
{
key:6,value:"x6"
},
{
key:7,value:"x7"
},
{
key:8,value:"x8"
},
{
key:9,value:"A"
},
{
key:10,value:"B"
},
{
key:11,value:"C"
},
{
key:12,value:"D"
}
];
const res = system.find(({key}) => key === 9);
console.log(res.value);

How to Sort Nested Array By Multiple Value in JavaScript

I need to sort nested array while sorting order and the sorting key will be dynamic. I am using the query but it work only on plain text.
Sample Data:
[
{
"modelId":1,
"modelCode":"model1",
"price":[
{
"PRICE_CODE1":225.01
},
{
"PRICE_CODE2":247.68
},
{
"PRICE_CODE3":298.0
}
]
},
{
"modelId":2,
"modelCode":"model2",
"price":[
{
"PRICE_CODE1":100.01
},
{
"PRICE_CODE2":200.68
},
{
"PRICE_CODE3":300.0
}
]
}
]
Expected Output:
[
{
"modelId":2,
"modelCode":"model2",
"price":[
{
"PRICE_CODE1":100.01
},
{
"PRICE_CODE2":200.68
},
{
"PRICE_CODE3":300.0
}
]
},
{
"modelId":1,
"modelCode":"model1",
"price":[
{
"PRICE_CODE1":225.01
},
{
"PRICE_CODE2":247.68
},
{
"PRICE_CODE3":298.0
}
]
}
]
as per the above example sorting is PRICE_CODE1, modelCode with ascending order. I am using the below query-
function sortByMultipleKey(keys) {
return function(a, b) {
if (keys.length == 0) return 0; // force to equal if keys run out
key = keys[0]; // take out the first key
if (a[key] < b[key]) return -1; // will be 1 if DESC
else if (a[key] > b[key]) return 1; // will be -1 if DESC
else return sortByMultipleKey(keys.slice(1))(a, b);
}
}
arr.sort(sortByMultipleKey(['PRICE_CODE1','modelCode']))
above query is working for plain arrays not for arrays of arrays because in example price is array. How to achieve this?
Warning: This would work for the price array structure you have but not for modelCode as sort key.
const data = [
{
"modelId":2,
"modelCode":"model2",
"price":[
{
"PRICE_CODE1":100.01
},
{
"PRICE_CODE2":200.68
},
{
"PRICE_CODE3":300.0
}
]
},
{
"modelId":1,
"modelCode":"model1",
"price":[
{
"PRICE_CODE1":225.01
},
{
"PRICE_CODE2":247.68
},
{
"PRICE_CODE3":298.0
}
]
}
]
function sortData(sortKeys = []) {
data.sort((a,b) => {
for (let sortKey of sortKeys) {
const priceObjA = a.price.find(x => sortKey in x);
const priceObjB = b.price.find(x => sortKey in x);
const priceA = priceObjA && priceObjA[sortKey] || 0;
const priceB = priceObjB && priceObjB[sortKey] || 0;
const result = priceA - priceB;
if (result !== 0) {
return result;
}
}
// fallback for equality
return 0;
})
}
sortData(['PRICE_CODE1']);
console.log(JSON.stringify(data,null,2));
sortData(['PRICE_CODE2']);
console.log(JSON.stringify(data,null,2));
sortData(['PRICE_CODE3']);
console.log(JSON.stringify(data,null,2));
arr.sort(sortByMultipleKey(['PRICE_CODE1','modelCode']))
Your sortByMultipleKey takes a list of keys, each of which describe one key. That can't describe the PRICE_CODE1 field of an object under prices.
You're essentially trying to come up with a syntax to describe arbitrary location in hierarchical data.
Instead of doing that, Use Javascript itself to define how to find the next comparison field! pass functions that can resolve the fields and iterate over those.
Below, I will define 2 functions. The first will extract the first PRICE_CODE1 from the elements of prices.
function(d) {
for (i = 0; i < d.price.length; d++) {
if ("PRICE_CODE1" in d.price[i]) {
return d.price[i].PRICE_CODE1
}
}
return undefined
}
The one for modelCode is simpler:
function(d) {
return d.modelCode
}
I also add a 3rd model with the same PRICE_CODE1 so that modelCode would also be relevant.
function sortByMultiple(field_funcs) {
return function(a, b) {
for (i = 0; i < field_funcs.length; i++) {
fa = field_funcs[i](a)
fb = field_funcs[i](b)
console.log("Comparing " + fa + " and " + fb)
if (fa < fb) return -1;
if (fa > fb) return 1;
if (i + 1 == field_funcs.length) return 0
}
}
}
var data = [{
"modelId": 2,
"modelCode": "model2",
"price": [{
"PRICE_CODE1": 100.01
},
{
"PRICE_CODE2": 200.68
},
{
"PRICE_CODE3": 300.0
}
]
},
{
"modelId": 1,
"modelCode": "model1",
"price": [{
"PRICE_CODE1": 225.01
},
{
"PRICE_CODE2": 247.68
},
{
"PRICE_CODE3": 298.0
}
]
},
{
"modelId": 3,
"modelCode": "model3",
"price": [{
"PRICE_CODE1": 225.01
},
{
"PRICE_CODE2": 247.68
},
{
"PRICE_CODE3": 298.0
}
]
}
]
data.sort(sortByMultiple([
function(d) {
for (i = 0; i < d.price.length; d++) {
if ("PRICE_CODE1" in d.price[i]) {
return d.price[i].PRICE_CODE1
}
}
return undefined
},
function(d) {
return d.modelCode
}
]))
console.log(data)
You can use lodash library:
_.orderBy( data, [c => c.price[0].PRICE_CODE1, "modelCode"], ["asc", "asc"]);

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

Add new attribute to JSON?

I have JSON data and I want to update items on it.
How can I add a name attribute to ALL id's in controller ?
{
"games" : [
{ "id":["1"] },
{ "id":["2"] },
{ "id":["3"] },
{ "id":["4"] },
{ "id":["5"] },
{ "id":["6"] }
]
}
Should be :
{
"games" : [
{ "id":["1"],"name":"1" },
{ "id":["2"],"name":"2" },
{ "id":["3"],"name":"3" },
{ "id":["4"],"name":"4" },
{ "id":["5"],"name":"5" },
{ "id":["6"],"name":"6" }
]
}
for (var i = 1; i <= games.length; i++) {
games[].name = i;
}
Use forEach to loop through every items of the data.games array and then simply add the name property using game.name = game.id[0].
const data = {
"games" : [
{ "id":["1"] },
{ "id":["2"] },
{ "id":["3"] },
{ "id":["4"] },
{ "id":["5"] },
{ "id":["6"] }
]
};
data.games.forEach(game => game.name = game.id[0]);
console.log(data);

How can I filter a JSON object in JavaScript?

I've got the following JSON string:
{
"Alarm":{
"Hello":48,
"World":3,
"Orange":1
},
"Rapid":{
"Total":746084,
"Fake":20970,
"Cancel":9985,
"Word": 2343
},
"Flow":{
"Support":746084,
"About":0,
"Learn":0
}
}
Then I load the above string and convert it to json object:
jsonStr = '{"Alarm":{"Hello":48,"World":3,"Orange":1},"Rapid":{"Total":746084,"Fake":20970,"Cancel":9985},"Flow":{"Support":746084,"About":0,"Learn":0}}';
var jsonObj = JSON.parse(jsonStr);
Now, how can I filter this json object by key name?
E.g., if the filter was "ange", the filtered object would be:
{
"Alarm":{
"Orange":1
}
}
If the filter was "flo", the filtered object would become:
{
"Flow":{
"Support":746084,
"About":0,
"Learn":0
}
}
And if the filter was "wor", the result would be:
{
"Alarm":{
"World": 3,
},
"Rapid":{
"Word": 2343
}
}
Is it possible to achieve this filtering using the filter method?
Beside the given solutions, you could use a recursive style to check the keys.
This proposal gives the opportunity to have more nested objects inside and get only the filtered parts.
function filterBy(val) {
function iter(o, r) {
return Object.keys(o).reduce(function (b, k) {
var temp = {};
if (k.toLowerCase().indexOf(val.toLowerCase()) !== -1) {
r[k] = o[k];
return true;
}
if (o[k] !== null && typeof o[k] === 'object' && iter(o[k], temp)) {
r[k] = temp;
return true;
}
return b;
}, false);
}
var result = {};
iter(obj, result);
return result;
}
var obj = { Alarm: { Hello: 48, "World": 3, Orange: 1 }, Rapid: { Total: 746084, Fake: 20970, Cancel: 9985, Word: 2343 }, Flow: { Support: 746084, About: 0, Learn: 0 }, test: { test1: { test2: { world: 42 } } } };
console.log(filterBy('ange'));
console.log(filterBy('flo'));
console.log(filterBy('wor'));
.as-console-wrapper { max-height: 100% !important; top: 0; }
You can create a function using reduce() and Object.keys() that will check key names with indexOf() and return the desired result.
var obj = {
"Alarm": {
"Hello": 48,
"World": 3,
"Orange": 1
},
"Rapid": {
"Total": 746084,
"Fake": 20970,
"Cancel": 9985,
"Word": 2343
},
"Flow": {
"Support": 746084,
"About": 0,
"Learn": 0
}
}
function filterBy(val) {
var result = Object.keys(obj).reduce(function(r, e) {
if (e.toLowerCase().indexOf(val) != -1) {
r[e] = obj[e];
} else {
Object.keys(obj[e]).forEach(function(k) {
if (k.toLowerCase().indexOf(val) != -1) {
var object = {}
object[k] = obj[e][k];
r[e] = object;
}
})
}
return r;
}, {})
return result;
}
console.log(filterBy('ange'))
console.log(filterBy('flo'))
console.log(filterBy('wor'))
With the filter method I think you mean the Array#filter function. This doesn't work for objects.
Anyway, a solution for your input data could look like this:
function filterObjects(objects, filter) {
filter = filter.toLowerCase();
var filtered = {};
var keys = Object.keys(objects);
for (var i = 0; i < keys.length; i++) {
var key = keys[i];
if (objects.hasOwnProperty(key) === true) {
var object = objects[key];
var objectAsString = JSON.stringify(object).toLowerCase();
if (key.toLowerCase().indexOf(filter) > -1 || objectAsString.indexOf(filter) > -1) {
filtered[key] = object;
}
}
}
return filtered;
}

Categories

Resources