JavaScript .sort override - javascript

I have an array of strings, which are all similar except for parts of them, eg:
["1234 - Active - Workroom",
"1224 - Active - Breakroom",
"2365 - Active - Shop"]
I have figured out that to sort by the ID number I just use the JavaScript function .sort(), but I cannot figure out how to sort the strings by the area (eg: "Workroom etc..").
What I am trying to get is:
["1224 - Active - Breakroom",
"2365 - Active - Shop",
"1234 - Active - Workroom"]
The "Active" part will always be the same.
From what I have found online, I have to make a .sort() override method to sort it, but I cannot figure out what I need to change inside the override method.

Example for you
var items = [
{ name: "Edward", value: 21 },
{ name: "Sharpe", value: 37 },
{ name: "And", value: 45 },
{ name: "The", value: -12 },
{ name: "Magnetic" },
{ name: "Zeros", value: 37 }
];
items.sort(function (a, b) {
if (a.name > b.name)
return 1;
if (a.name < b.name)
return -1;
// a must be equal to b
return 0;
});
You can make 1 object to describe your data .
Example
data1 = { id : 12123, status:"Active", name:"Shop"}
You can implement your logic in sort().
Return 1 if a > b ;
Return -1 if a < b
Return 0 a == b.
Array will automatically order follow the return
Hope it'll help.

You can give the sort method a function that compares two items and returns the order:
yourArray.sort(function(item1, item2){
// compares item1 & item2 and returns:
// -1 if item1 is less than item2
// 0 if equal
// +1 if item1 is greater than item2
});
Example in your case :
yourArray.sort(function(item1, item2){
// don't forget to check for null/undefined values
var split1 = item1.split(' - ');
var split2 = item2.split(' - ');
return split1[2] < split2[2] ? -1 : (split1[2] > split2[2] ? 1 : 0);
});
see Array.prototype.sort()

You don't have to override anything, just pass .sort custom function that will do the sorting:
var rsortby = {
id : /^(\d+)/,
name : /(\w+)$/,
status : /-\s*(.+?)\s*-/,
};
var r = rsortby['name'];
[
'1234 - Active - Workroom',
'1224 - Active - Breakroom',
'2365 - Active - Shop',
].
sort(function(a, b) {
var ma = a.match(r)[1];
var mb = b.match(r)[1];
return (ma != mb) ? (ma < mb ? -1 : 1) : 0;
});
// ["1224 - Active - Breakroom", "2365 - Active - Shop", "1234 - Active - Workroom"]
//

Related

Javascript - Sorting array with objects based on objects value

So I am trying to sort my array with objects based on an objects value..
var mostCheapHistory [ { lowestTitle: title goes here, lowestPrice: 100 }, another obj, another, another } ]
And I want to sort them based on their price, so I came up with this:
var historyObj = mostCheapHistory[0];
for(var y in mostCheapHistory){
nextObj = mostCheapHistory[y];
console.log('Is '+ historyObj.lowestPrice + ' more as ' + nextObj.lowestPrice + ' ?');
console.log(historyObj.lowestPrice > nextObj.lowestPrice);
console.log('-----')
}
And this is the output...
Is 124.98 more as 124.98 ?
false
-----
Is 124.98 more as 18.59 ?
false
-----
Is 124.98 more as 25.9 ?
false
-----
Is 124.98 more as 26.99 ?
false
-----
Is 124.98 more as 34.76 ?
false
-----
What the hell is going on? It's obvious that 124.98 is more as 34.76 and yet it gives false?
The array is made using this code:
for(var x=0; x < items.length; x++){
var title = items[x].title[0];
var price = items[x].sellingStatus[0].currentPrice[0].__value__;
var item =
{
lowestPrice : price,
lowestTitle : title
}
if(x === 0){
mostCheapHistory.push(item);
}
else{
for(var y=0; y < mostCheapHistory.length; y++){
if(mostCheapHistory[y].lowestPrice > price ){
if(mostCheapHistory.length < 5){
mostCheapHistory.push(item);
break;
}
else{
mostCheapHistory[y] = item;
break;
}
}
}
}
}
Use the predefined sort function :
mostCheapHistory.sort(function(a,b){
return a.lowestPrice - b.lowestPrice;
}
+ Your code might be pushing strings rather than numbers, which explains why 124.98 > 34.76 => true but '124.98' > '34.76' => false, since the string '34.76' is greater than '124.98' in string comparison.
Use parseFloat() for the prices then check again.
It looks like, you are comparing strings instead of numerical values. If you say (in comments), that the sorting function
array.sort((a, b) => a.lowestPrice - b.lowestPrice);
solves your problem, then while this sort callback uses an implicit casting to number with the minus - operator.
The result is a sorted array with values as string.
You can sort these based on price using Array.prototype.sort() (See MDN documentation)
e.g.
var data = [
{
title: "title1",
value: 123
},
{
title: "title2",
value: 324
},
{
title: "title3",
value: 142
}];
var sorted = data.sort(function(a, b) {
return a.value > b.value;
});
I think the type of lowestPrice is string not float, use parseFloat(historyObj.lowestPrice) to compare the two values

How to get the last N objects before a certain object in a Javascript array?

I'm trying to implement the endless loading of items in Javascript. Like the effect you get when you scroll through your messages in your favorite messaging application. I have a big array like this (+1000 objects):
var array = [
{ id : 1, text: "First"},
{ id : 2, text: "Second"},
{ id : 3, text: "Third"},
{ id : 4, text: "Forth"},
{ id : 5, text: "Fifth"},
{ id : 6, text: "Sixth"},
{ id : 7, text: "Seventh"},
...
];
Now I want to load only 10 items at a time. For example I'm showing only the items with the id of 30 to 39. Now the user wants to see the items before 30. What is the best way to select last 10 items before that object with the id of 30? As mentioned before, the array's size is big so performance does matter here.
EDIT
The example above is just one case. I should be able to filter my array 10 items at a time as many times as needed.
What I'm trying to achieve is loading a big array but not all at once. I want to load 10 items at a time. I'm keeping track of the first object in my filtered array (e.g 30) and then I want to get the last 10 objects before that particular object.
EDIT 2
This is my View:
<div ng-repeat="message in messages" class="message-wrapper">
// Show content of message
</div>
Now initially i'm showing the last 10 items in messages
$scope.init = function(){
var messages = Database.AllMessages(); // This function returns all my messages
$scope.messages = messages.length > 10 ? messages.slice(-10) : messages;
}
Now let's say the items returned by this function are the items with the Id of 30 to 39. The user scrolls up and wants to see the messages prior to 30. So how can i filter the whole array returned by AllMessages() to get 10 last items before the 30 message?
Thanks in advance for any insights.
You want to query your data source as efficient as possible. Make sure the array is sorted by id first:
array.sort(function(a, b) {
if (a.id === b.id) return 0;
if (a.id > b.id) return 1;
return -1;
});
Then, binary search can be performed to find the index of the element you're looking for:
var search = function(arr, val) {
if (arr.length === 0) {
return -1;
}
var max = arr.length - 1, min = 0;
while (max !== min) {
var index = Math.floor((max + min) / 2);
if (arr[index].id === val) {
return index;
}
else if (arr[index].id < val) {
min = index;
}
else {
max = index;
}
}
return arr[index].id === val ? index : -1;
}
// find index of element with desired id.
var index = search(array, 30);
Once we know the index, we simply have to select the elements before/after the index:
var rangeMin = index - 10; // Inclusive. 10 is the maximum number of elements you want to render.
var rangeMax = index; // Not inclusive.
if (rangeMin < 0) { rangeMin = 0; }
if (rangeMax > array.length) { rangeMax = array.length; }
var elementsToRender = array.slice(rangeMin, rangeMax);
elementsToRender will now contain all the elements you want to render.
Now let's say the items returned by this function are the items with the Id of 30 to 39. The user scrolls up and wants to see the messages prior to 30. So how can i filter the whole array returned by AllMessages() to get 10 last items before the 30 message?
(...) my view should show the items 20 to 39
Suppose allMessages contains all messages (very large array).
Suppose ctrl is a controller instance
Suppose ctrl.messages contains the items currently displayed.
Suppose currentIndex is 30
Suppose stepSize is 10
Then the following code will extend messages to contain items 20 to 39 and will set currentIndex to 20:
currentIndex -= stepSize; // the new first message will have index 20
var extraItems = allMessages.slice(currentIndex, currentIndex+stepSize);
Array.prototype.push.apply(extraItems, ctrl.messages); // append ctrl.messages to extraItems
ctrl.messages = extraItems;
For more information about Array.prototype.push.apply, see Mozilla (scroll down to 'Merging two arrays').
Here is small app to demonstrate it (you'll have to add logic to protect the user to cross the array boundaries):
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.2/angular.min.js"></script>
<script>
var myApp = angular.module('myApp', []);
myApp.controller('MyController', function() {
var ctrl = this;
var allMessages = Database.AllMessages();
var stepSize = 10;
var currentIndex = allMessages.length - stepSize;
// show the last 10 messages
ctrl.messages = allMessages.length > 10 ? allMessages.slice(-10) : allMessages;
// show ten more messages
ctrl.showMore = function () {
currentIndex -= stepSize;
var extraItems = allMessages.slice(currentIndex, currentIndex+stepSize);
Array.prototype.push.apply(extraItems, ctrl.messages);
ctrl.messages = extraItems;
};
});
</script>
</head>
<body ng-app="myApp">
<div ng-controller="MyController as ctrl">
<table>
<tr ng-repeat="message in ctrl.messages"><td>{{message.text}}</td></tr>
</table>
<button ng-click="ctrl.showMore();">show more</button>
</div>
</body>
</html>
You can try this to get the object with id 30 without a loop using the following code:
var array = [
{ id : 1, text: "First"},
{ id : 2, text: "Second"},
{ id : 3, text: "Third"},
{ id : 4, text: "Forth"},
{ id : 5, text: "Fifth"},
{ id : 6, text: "Sixth"},
{ id : 7, text: "Seventh"}
];
var result = $.grep(array, function(e){ return e.id == 5; });
console.log(result);
What is the best way to select last 10 items before that object with the id of 30?
var index = 30;
var count = 10;
// 10 items before 30 :
array.slice(index-count, index);
I knew this thing I made could be helpful to somebody. Here's the relevant piece:
$('button.getResult').on('click', function(e) {
e.preventDefault();
var limit = $('input.getResult').val();
if (limit != '' && !isNaN(limit)) {
var dots = $('ul li');
if (dots.length > limit) {
//show the limit as group
var foundSelected = false;
var counter = 0;
for (var i = dots.length - 1; i >= 0; i--) {
dots.eq(i).addClass('group');
dots.eq(i + parseInt(limit)).removeClass('group');
counter++;
if (i == $('li.selected').index()) {
foundSelected = true;
};
if (foundSelected && counter >= limit) {
i = -1;
};
};
} else {
//show all as group
dots.addClass('group');
};
};
return false;
});
dots is basically your array and the first conditional is just checking to make sure the number of results you want is smaller than the length of the array. Then a loop is performed through the array (backwards in my case) checking for the important item. If I find it, I change the boolean to true.
Additionally, I mark each as selected as I iterate and if the selected index is outside of the limit of pagination, then I remove the selected mark (to keep the pagination). Once I've both found the important item and have marked the correct number of items past the important one, I stop the loop.
Of course, you might not be able to mark things in your case but I figure you could look at this for some inspiration.

sorting of array manually in javascript

I have an array of strings like below.
ABC
QRS
DEF
HIJ
TUV
KLM
NOP
I need to sort this array in javascript in alphabetical order, except for few values which is already known. ie I need DEF and NOP comes in the first 2 positions and sort rest of the array alphabetically in ascending order. Here is what I've written to sort the entire array in alphabetical order, now I need the 2 values in the first 2 positions.
array.sort(function(a,b){return ((a < b) ? -1 : (a > b) ? 1 : 0)});
Expected result.
DEF
NOP
ABC
HIJ
KLM
QRS
TUV
The contents of the array is dynamic, so if the array has DEF or NOP, then those should be on top, if else, it should be sorted alphabetically. Whats the best way to approach this?
I think the most straightforward way would be to remove the known elements separately instead of trying to incorporate them into the sort. That way, you can also just sort without a comparison function.
function sortWithKnownPrefix(prefix, arr) {
// Get the non-prefix elements
var rest = arr.filter(function (item) {
return prefix.indexOf(item) === -1;
});
// Concatenate the prefix and the sorted non-prefix elements
return prefix.concat(rest.sort());
}
sortWithKnownPrefix(
["DEF", "NOP"],
["ABC", "QRS", "DEF", "HIJ", "TUV", "KLM", "NOP"]
)
// ["DEF", "NOP", "ABC", "HIJ", "KLM", "QRS", "TUV"]
If you want to allow for, count and hoist multiple instances of those strings: http://jsfiddle.net/4hgnjqas/1/
The following will count all known instances of the strings you want to hoist to the front, remove them from the existing array, sort it, then add the same number of "DEF"s and "NOP"s to the array.
var hoist = {"NOP":0, "DEF":0}
for(var p in hoist)
while(array.indexOf(p)>-1){
array.splice(array.indexOf(p),1);
hoist[p]++;
}
arr.sort();
for(var p in hoist){
for(var i=0;i<hoist[p];i++)
array.unshift(p);
}
console.log(array);
This will reposition 'DEF' and 'NOP' after sorting the rest of the items:
function customSort(array) {
array = array.sort(function(a,b){
return (a < b) ? -1 : (a > b) ? 1 : 0;
});
var NOPIndex = array.indexOf('NOP');
if (NOPIndex > -1)
array.unshift(array.splice(NOPIndex, 1)[0]);
var DEFIndex = array.indexOf('DEF');
if (DEFIndex > -1)
array.unshift(array.splice(DEFIndex, 1)[0]);
return array;
}
this could be the simpler one
var arr = ['ABC','QRS','DEF','HIJ','TUV','KLM','NOP']
var exclude = ['DEF', 'NOP'];
arr.sort(function(a,b) {
if(exclude.indexOf(a) > -1 && exclude.indexOf(b) > -1)
return ((a < b) ? -1 : (a > b) ? 1 : 0);
if(exclude.indexOf(b) > -1)
return 1;
return ((a < b) ? -1 : (a > b) ? 1 : 0)
});
alert(JSON.stringify(arr)) //result
JS Fiddle *UPDATED

Javascript array of objects will not sort, despite setting sort function

I have an array of objects, in which each contains several numerical values. Here is the layout of the object:
{
v: [],
cm: 0
}
This is the definition of the sort function:
registry.sort(function(a,b) {return (a.cm > b.cm) ? 1 : ((b.cm > a.cm) ? -1 : 0);} );
When I run the sort function, it does nothing whatsoever, just leaves the array the way it was. I am new to js, but as far as I can tell, everything should be working. Does anyone know what is wrong?
Thanks
EDIT: here is the smallest example I can extract
var registry = [];
registry.sort(function(a,b) {return (a.cm > b.cm) ? 1 : ((b.cm > a.cm) ? -1 : 0);} );
var draw = function() {
//various other function calls that add values to the registry array
registry[0] = {v:[0,0,0], cm:3}; //just to have something to use in the variable
registry[1] = {v:[0,0,0], cm:2};
debug(registry[0], registry[1]);
registry.sort();
debug(registry[0], registry[1]);
}
The sort() is not a configuration. When you call it, it does the sort. You can do this:
var comparator = function(a,b) {return (a.cm > b.cm) ? 1 : ((b.cm > a.cm) ? -1 : 0);}
for (var i = 0; i < regPos; i++) {
debug(registry[i], "eah");
}
registry.sort(comparator);
registry.reverse();
for (var i = 0; i < regPos; i++) {
debug(registry[i]);
}
Or simply
var comparator = function(a,b) {return a.cm - b.cm;}
The code below will sort the array "points" which has a similar structure... not sure if this is an exact match for your data though.
var points = [{v:[1,2,3],cm:40},{v:[2], cm:100},{v:[], cm:1},{cm:5,v:[]},{v:[3],cm:25},{cm:10}];
points.sort(function(a,b) {return (a.cm - b.cm);});
for (x in points) {
console.log(points[x]);
}
Are you sure the "cm" field is defined for every record in your array?

Show arrays arranged in a specific format

I have the following array in JavaScript:
myArray = ["lu9","lu10","lu11","ma9","ma10","ma11","mi9","mi10","mi11"];
Then, I need to display the values ​​(for example in an alert) but must be arranged as follows:
"lu9,ma9,mi9,lu10,ma10,mi10,lu11,ma11,mi11"
How I can do this?
Each item in your list has two parts: The leading mishmash of characters (mi, ma, lu) and a numerical suffix. To properly sort, we have to take both into account.
array.sort(function sorter (a, b) {
var re = /^(\D+)(\d+)$/,
left = re.exec(a),
right = re.exec(b);
if (left[1] === right[1]) {
return Number(left[2]) - Number(right[2]);
}
return left[1] < right[1] ? -1 : 1;
});
Let's say a = lu9 and b = lu10:
1. left = ['lu9', 'lu', '9']
2. right = ['lu10', 'lu', '10']
3. left[1] === right[1]
1. Number(left[2]) = 9
2. Number(right[2]) = 10
3. return 9 - 10 (negative number, a before b)
Now if our input is a = lu9 and b = mi4:
1. left = ['lu9', 'lu', '9']
2. right = ['mi4', 'mi', '4']
3. left[1] !== right[1]
1. left[1] < right[1] = true
2. return -1
var myArray = ["lu9", "lu10", "lu11", "ma9", "ma10", "ma11", "mi9", "mi10", "mi11"];
function myResult(myArray) {
myArray = myArray.slice().sort(function (a, b) {
var reg = /\d+/ //A regex to extract the numerical part
var num = 2 * (+a.match(reg) - +b.match(reg)) //Put a weight of 2 on the numerical value
var str = a > b ? 1 : a < b ? -1 : 0 //The strings value with a single weight
return num + str //add them and we have a positive or negative value with a correct weight on the numerical part
})
return "" + myArray
}
console.log (myResult(myArray)) //"lu9,ma9,mi9,lu10,ma10,mi10,lu11,ma11,mi11"
Heres a Fiddle
var myArray = ["lu9","lu10","lu11","ma9","ma10","ma11","mi9","mi10","mi11"];
var derp = function(a, b) {
a = a.replace(/[^0-9]+/g, '', a);
b = b.replace(/[^0-9]+/g, '', b);
return a < b;
}
myArray.sort(derp);
We need to sort first by number and then by letters.
no need for regex here.
We will use padding:
so ma11 will be 0011ma
and mi11 will be 0011mi
and ma11 will be 0011ma
(and mi9 will be 0009mi , the padding helps 11 to be bigger then 2 as string)
so sorting it now - will yield the right result.
var a = ["ma9", "ma10", "ma11", "mi9", "mi10", "mi11", "lu9", "lu10", "lu11"]
a.sort(function (a, b)
{
return calc(a) > calc(b);
});
function calc(x)
{
return ("0000" + x.slice(2)).slice(-4) + x.slice(0,2);
}
result :
["ma9", "ma10", "ma11", "mi9", "mi10", "mi11", "lu9", "lu10", "lu11"]

Categories

Resources