'JS array sort with regex
My objective is to sort an array based on the priority of JS object that uses regular expressions. Here's what I have:
JS objects defined:
var rx_CondoIndicator = new RegExp(/\bCONDO(MINIUM)?(?!S)/);
var rx_TownhouseIndicator = new RegExp(/\bTOWN\s*(HOUSE|HOME)(?!S)/);
var rx_TimeshareIndicator = new RegExp(/\bTIMESHARE(?!S)/);
Sort objects defined:
var so_UnitKeywordIndicator = {
rx_CondoIndicator: 1,
rx_TownhouseIndicator: 2,
rx_TimeshareIndicator: 3
};
arrUnitNumber = ['TIMESHARE A-1', 'TOWNHOUSE 407', 'CONDO #13']
The following logic ignores the sort object priority and does not sequence the array in the desired order which is "CONDO #13", "TOWNHOUSE 407", "TIMESHARE A-1"
arrUnitNumber.sort(function(x,y){
return so_UnitKeywordIndicator[x] - so_UnitKeywordIndicator[y];
})
Please note that only a fraction of the JS sort objects are shown for brevity.
If this is not the best solution for the problem, I'm open to any suggestions being a novice at JS.
Solution 1:[1]
The main problem is that you're never using your regular expressions for anything in the sort loop, and x and y will be entries from the array ('TIMESHARE A-1' and similar), which don't exist on so_UnitKeywordIndicator as properties. So so_UnitKeywordIndicator[x] will always be undefined.
It looks like you want to use the regular expressions to categorize the strings, and then sort them based on the relatives values in so_UnitKeywordIndicator. So you'll need to test the strings against the regular expressions.
If you have to start from those strings, I think I'd probably approach it like this (removing so_UnitKeywordIndicator):
arrUnitNumber.sort(function(x,y){
return getSortingKey(x) - getSortingKey(y);
});
function getSortingKey(value) {
if (rx_CondoIndicator.test(value)) {
return 1;
}
if (rx_TownhouseIndicator.test(value)) {
return 2;
}
if (rx_TimeshareIndicator.test(value)) {
return 3;
}
return 4;
}
Live Example:
var rx_CondoIndicator = /\bCONDO(MINIUM)?(?!S)/;
var rx_TownhouseIndicator = /\bTOWN\s*(HOUSE|HOME)(?!S)/;
var rx_TimeshareIndicator = /\bTIMESHARE(?!S)/;
var arrUnitNumber = ['TIMESHARE A-1', 'TOWNHOUSE 407', 'CONDO #13'];
arrUnitNumber.sort(function(x, y) {
return getSortingKey(x) - getSortingKey(y);
});
arrUnitNumber.forEach(function(entry) {
snippet.log(entry);
});
function getSortingKey(value) {
if (rx_CondoIndicator.test(value)) {
return 1;
}
if (rx_TownhouseIndicator.test(value)) {
return 2;
}
if (rx_TimeshareIndicator.test(value)) {
return 3;
}
return 4;
}
<!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script>
If there are a lot of entries, though, that's inefficient because it has to recalculate the sorting key every time two entries in the array are compared, and so does it repeatedly even for the same value (potentially). So if there are a large number of entries, you're probably best off building an array of objects with the sort key on them instead:
var unitObjects = arrUnitNumber.map(function(entry) {
return {
str: entry,
key: getSortingKey(entry)
};
});
unitObjects.sort(function(x, y){
return x.key - y.key;
});
Then either just use that array, or if you want strings again, just map at the end:
arrUnitNumber = unitObjects.map(function(entry) {
return entry.str;
});
But again, only if there are a lot (lot) of entries in the array.
Live Example:
var rx_CondoIndicator = /\bCONDO(MINIUM)?(?!S)/;
var rx_TownhouseIndicator = /\bTOWN\s*(HOUSE|HOME)(?!S)/;
var rx_TimeshareIndicator = /\bTIMESHARE(?!S)/;
var arrUnitNumber = ['TIMESHARE A-1', 'TOWNHOUSE 407', 'CONDO #13'];
var unitObjects = arrUnitNumber.map(function(entry) {
return {
str: entry,
key: getSortingKey(entry)
};
});
unitObjects.sort(function(x, y){
return x.key - y.key;
});
unitObjects.forEach(function(entry) {
snippet.log(entry.str);
});
function getSortingKey(value) {
if (rx_CondoIndicator.test(value)) {
return 1;
}
if (rx_TownhouseIndicator.test(value)) {
return 2;
}
if (rx_TimeshareIndicator.test(value)) {
return 3;
}
return 4;
}
<!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script>
Side note: You don't need (or want) the new RegExp( part where you're defining your regular expressions, JavaScript is unusual in that it has regular expression literals (like string literals); that's what you have in your /.../:
var rx_CondoIndicator = /\bCONDO(MINIUM)?(?!S)/;
var rx_TownhouseIndicator = /\bTOWN\s*(HOUSE|HOME)(?!S)/;
var rx_TimeshareIndicator = /\bTIMESHARE(?!S)/;
Solution 2:[2]
just for sharing my problem & solution. I need to order my format data by tag.
const nameTagDatas = ["name(ddd)", "name(ccc)", "name(bbb)", "name(aaa)"];
const tagOrder = ["aaa", "bbb", "ccc", "ddd"];
nameTagDatas.sort(
(a, b) =>
tagOrder.findIndex((e) => a.search(new RegExp("\\(" + e + "\\)")) != -1) -
tagOrder.findIndex((e) => b.search(new RegExp("\\(" + e + "\\)")) != -1)
);
console.log(nameTagDatas) // [ 'name(aaa)', 'name(bbb)', 'name(ccc)', 'name(ddd)' ]
extract function
nameTagDatas.sort(
(a, b) => findIndexByTag(tagOrder, a) - findIndexByTag(tagOrder, b)
);
function findIndexByTag(_orderArr, _searchStr) {
return _orderArr.findIndex(
(e) => _searchStr.search(new RegExp("\\(" + e + "\\)")) != -1
);
}
Solution 3:[3]
You can use .match(/<regex>/)
Here is JS
let wordsArr = ['2.World', '1.Hello'];
const regex = /\d/
let answer = wordsArr.sort((a,b) => {
return a.match(regex) - b.match(regex);
});
console.log('answer', answer);
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | |
| Solution 2 | |
| Solution 3 | shahul01 |
