Lodash does not sort objects correctly - javascript

I'm trying to sort objects based by its property (price)
var arr = [{
name: 'Apple',
price: '1.03'
},
{
name: 'Cherry',
price: '0.33'
},
{
name: 'Mango',
price: '0.53'
}
]
Now i use lodash to sort it by its price:
arr = _.sortBy(arr, 'price' ).reverse();
Now arr[0] should be Apple, since it's price is highest, but it's not.
What could be wrong?

As everyone is mentioning you are sorting Strings so your outcome is not what you are expecting. To sort based on price use the following (or similar):
var arr = [{
name: 'Apple',
price: '1.03'
},
{
name: 'Cherry',
price: '0.33'
},
{
name: 'Mango',
price: '0.53'
}
]
arr.sort(function(a, b){
return parseFloat(b.price) - parseFloat(a.price);
});
console.log(arr);

Since there isn't an answer using Lodash here, I am going to provide one in case someone else stumbles across this question in the future:
// Your code:
var arr = [{
name: 'Apple',
price: '1.03'
},
{
name: 'Cherry',
price: '0.33'
},
{
name: 'Mango',
price: '0.53'
}
]
// Yours that isn't working:
// arr = _.sortBy(arr, 'price' ).reverse();
const sortedArr = _.chain(arr)
.map((val) => _.toNumber(val.price))
.sortBy()
.value();
console.log(sortedArr);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.5/lodash.min.js"></script>

Since the price value inside each object is a string, you are getting a different result. You can take advantage of function callback and convert your price value to a number and the use sortBy to sort your data based on the numeric value of price.
var arr = [{name: 'Apple',price: '1.03'},{name: 'Cherry',price: '0.33'},{name: 'Mango',price: '0.53'}];
_.sortBy(arr, ({price}) => +price);
console.log(arr);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.5/lodash.min.js"></script>

If you are using LoDash, this is how i did it:
var arr = [{name: 'Apple',price: '1.03',weight:'12'},{name: 'Cherry',price: '0.33',
weight:'12',weight:'12'},{name: 'Mango',price: '0.53',weight:'12'}];
SortyBy(sortName, SortType, order)
{
if(SortType == 1)
{
_.orderBy(arr,[function(o) { return parseFloat(o[sortName]); }],order);
}
else
{
_.orderBy(arr,[function(o) { return o[sortName]; }], order);
}
}
//you would then call:
SortBy("price",1, "asc");
SortBy("weight",1, "asc");
SortBy("name",0,"desc");`

Related

JavaScript: How to add and sort the same fields in an array based on fields?

I have the following array a as shown below:
var a = [
{name: 'phone' , id:1 ,num:1},
{name: 'milk' ,id:2, num:1},
{name: 'apple' , id:3 , num:1},
{name: 'phone', id: 4, num:3},
]
I want to filter by array name and add their own num
var currentName = a[0]
let newArrys=[]
for(let i = 0; i<a.length;i++){
if(currentName.name == a[i].name){
a[i].num = a[i].num + currentName.num
let tmepArry = [];
tempArry.push(a[i]);
newArrys.push(tempArry);
}
}
I am trying to obtain the following 2D array:
[
[{name: 'phone', id:1, num:4}],
[{name: 'milk',id:2, num:1}],
[{name: 'apple', id: 3 num:1}]
]
The result cannot be screened out.
My attempt is invalid.
Can you help me?
Given:
var a = [
{name: 'phone' , id:1 ,num:1},
{name: 'milk' ,id:2, num:1},
{name: 'apple' , id:3 , num:1},
{name: 'phone', id: 4, num:3},
]
const newArrys = a.reduce((acc, current) => {
// find an object in the array with a matching name
const existing = acc.find(obj => obj.name === current.name);
if (existing) {
// combine the numbers
existing.num += current.num;
} else {
acc.push(current);
}
return acc;
}, []).map(obj => [obj])
That will get you what you need.
Here's a quick example of how to go about it. Essentially it's a two step process that involves first reducing your array of objects into a distinct list with the counts (num). Then, iterating over your results to create your 2D array.
There's probably a fancier way to produce the same result by adding a little bit more code to the reducer, but trying to go for readability here as it's rather easy to get lost in reduce functions.
var a = [
{name: 'phone' , id:1 ,num:1},
{name: 'milk' ,id:2, num:1},
{name: 'apple' , id:3 , num:1},
{name: 'phone', id: 4, num:3},
]
// Get the counts using reduce
const results = a.reduce( (acc, curr) => {
if (acc.hasOwnProperty(curr.name)) {
acc[curr.name].num += curr.num;
} else {
acc[curr.name] = {id: curr.id, num: curr.num };
}
return acc;
}, {});
// Establish result array
const finalResult = [];
// Iterate over results object and format them into an array of a single object
// then push the array to the finalResult array (thus making it 2D)
for (const key in results) {
const item = results[key];
finalResult.push([{ name: key, id: item.id, num: item.num }]);
}
console.log(finalResult);
Not sure if this is the best solution but it does work. Please feel free to give advise on what I should have done instead for a better code. Haha..
var a = [
{name: 'phone' , id:1 ,num:1},
{name: 'milk' ,id:2, num:1},
{name: 'apple' , id:3 , num:1},
{name: 'phone', id: 4, num:3},
]
function organize_array(tmpArray) {
let data = []
tmpArray.forEach(function(value, key) {
if(data.filter(tmp => tmp.name == value.name) == '') {
const tmpFiltered = a.filter(tmp => tmp.name == value.name)
let total = 0
tmpFiltered.map(x => { total += x.num })
data.push({name: value.name, num: total})
}
})
return data
}
console.log(organize_array(a))

Add key-value pair in Javascript object

I have an object in Javascript. I want to add key-value pair in it.
var data = {
Country1: '20',
country2: '30',
country3: '40',
country4: '45'
};
It should look like,
var data = {
{name: 'country1', values: '20'},
{name: 'country2', values: '30'},
{name: 'country3', values: '40'},
{name: 'country4', values: '45'},
};
I am looking for a solution where from a given object, country names will automatically fall into name and values into values
Iterate the Object#keys of the object with Array#map, and return an object in the format that you want.
Note: to ensure the order of the objects, you can sort the keys using String#localeCompare with the numeric: true option.
var data = {
'Country1' : '20',
'country2': '30',
'country3': '40',
'country4' : '45'
};
var result = Object.keys(data)
.sort(function(a, b) { // if you need to ensure the order of the keys
return a.localeCompare(b, undefined, { numeric: true})
})
.map(function(key) {
return {
name: key,
value: data[key]
};
});
console.log(result);
Use Objecy.Keys and forEach to loop through the Objects,
var data = {
'Country1' : '20',
'country2': '30',
'country3': '40',
'country4' : '45'
};
var result = [];
Object.keys(data).forEach(key => {
result.push({'name':key,'value':data[key]});
});
console.log(result);
or use Object.entries :
data = Object.entries(data).map(([name, values]) => ({name, values}));

How search two arrays and find if there is a match?

I have an array :
[{name:'blah',id:1},{name:'blah2',id:3}]
I have another array :
[{type:'blah',uid:3435},{type:'blah2',uid:3}]
I want to end up with :
[{newname:'blah2',uidid:3}]
You can see I want to match the two based on a mapping of id=uid. Really struggling to find a way to do this in js. I have underscore installed.
You could build a hash table with the first array and use it in the iteration of the second array.
var array1 = [{ name: 'blah', id: 1 }, { name: 'blah2', id: 3 }],
array2 = [{ type: 'blah', uid: 3435 }, { type: 'blah2', uid: 3 }],
hash = Object.create(null),
match = [];
array1.forEach(function (a) {
hash[a.id] = a;
});
array2.forEach(function (a) {
hash[a.uid] && match.push({ newname: a.type, uidid: a.uid });
});
console.log(match);
Since you are wanting an array with an object that uses different key names, something like this will work. It is also simple to read and to understand without any complex syntax or logic.
var arr1 = [{name: 'blah', id: 1}, {name: 'blah2', id: 3}];
var arr2 = [{type: 'blah', uid: 3435}, {type: 'blah2', uid: 3}];
var arr3 = [];
arr1.forEach(function(obj1, i) {
arr2.forEach(function(obj2) {
if (obj1.id == obj2.uid) {
arr3.push({newname: obj1.name, uidid: obj1.id})
}
})
});
console.log(arr3);

How to sort Array by alpha of a specific key inside each object?

Example of my Array =
[{
name: leon,
id: 1
}, {
name: laura
id: 20003
}, {
name: anne
id: 45
}]
Currently in the UI, the array will look like:
leon
laura
anne
How can one use lodash to sort the array by the name keys in alphabetical order?
_.sortBy(myObjects, 'name');
Name is the sort key here
You could use a proper callback.
var array = [{ name: 'leon', id: 1}, { name: 'laura', id: 20003}, { name: 'anne', id: 45}];
array.sort(function (a, b) {
return a.name.localeCompare(b.name);
});
console.log(array);
You do not need lodash to do that...
Just do
var sortedNames = names.sort(function(a, b) {
return a.name.localeCompare(b.name);
});
jsFiddle: https://jsfiddle.net/p07c4oaa/
Or wrap that in a function like:
function sortBy(obj, key) {
return obj.sort(function(a, b) {
return a[key].localeCompare(b[key]);
});
}
jsFiddle: https://jsfiddle.net/p07c4oaa/1/
Not sure of loadash but you can use simple sort method to sort the json array of objects
var arry=[{
name: 'leon',
id: 1
}, {
name: 'laura',
id: 20003
}, {
name: 'anne',
id: 45
}]
var sorted = arry.sort(function(a,b){
return a.name > b.name ? 1:-1
})
// this part just for demo
sorted.forEach(function(item){
document.write('<pre>'+item.name+'</pre>')
})
JSFIDDLE

How do I reorder this array in Javascript based on another array?

real_order = [ '1', '2', '3', '4'];
friends = [ { name: 'jess', id: '4'},
{ name: 'alex', id: '1'},
{ name: 'kat', id: '3' },
{ name: 'bob', id: '2' }
]
How do I make "friends" array "match" the elements in real_order?
The result should be:
[
{ name: 'alex', id: '1'},
{ name: 'bob', id: '2' },
{ name: 'kat', id: '3' },
{ name: 'jess', id: '4'},
]
What is the most efficient solution?
Here is some code that would do it:
var i, d = {}, result = [];
for(i=0; i<friends.length; ++i)
{
d[friends[i].id] = friends[i];
}
for(i=0; i<real_order.length; ++i)
{
result.push(d[real_order[i]]);
}
What this does is it creates a dictionary keyed on each of the friends' id, then uses the second array to do a look up and construct the new array. The resulting reordered array is stored in result.
Arrays can be sorted using your own custom sort algorithm, so you don't really need real_order. This is the way I'd do it (edit: added sort delegate for sorting descending):
var friends = [
{ id:4, name: 'jess'},
{ id:1, name: 'alex'},
{ id:3, name: 'kat' },
{ id:2, name: 'bob' }
];
var order = function(a,b,desc){
return desc ? b.id - a.id : a.id - b.id;
},
orderDesc: function(a,b){return order(a,b,true);};
var friendsOrdered = friends.sort( order );
alert(friendsOrdered[0].name); //=> alex
alert(friendsOrdered[3].name); //=> jess
//or sort descending
var friendsOrdered = friends.sort( orderDesc );
alert(friendsOrdered[0].name); //=> jess
alert(friendsOrdered[3].name); //=> alex
make sure that real_order is in global scope and this should do it:
friends.sort(function(a, b) {
if (real_order.indexOf(a.id) > real_order.indexOf(b.id)) {
return 1;
}else{
return -1;
}
});
One command solution. Ugly like jQuery, but people like John Resig love this style for some reason :)
friends.sort(
(function(order){
return function(a, b) {
return order.indexOf(a.id)-order.indexOf(b.id);
}
})(real_order)
);

Categories

Resources