Reputation: 1016
I'm ordering an array using lodash/orderBy. I have no control over what comes back in the array. When my array items have new lines in them, then then they don't order as I expect them to. Is there any way to ignore the new lines? Or any other way to get the items to order correctly?
const shouldBeFirst = 'My message\r\n\r\nshould consist of A A A A some
text';
const shouldBeSecond= 'My message\r\n\r\nshould consist of \r\n\r\n some
text';
const array = [
{ text: 'xxx' },
{ text: shouldBeFirst },
{ text: 'yyy' },
{ text: shouldBeSecond},
{ text: 'zzz' }];
const ordered = orderBy(array, ['day'], ['asc']);
The order I expect to get these items in is
{ text: shouldBeFirst },
{ text: shouldBeSecond},
{ text: 'xxx' },
{ text: 'yyy' },
{ text: 'zzz' }];
However the order I get them in is:
{ text: shouldBeSecond },
{ text: shouldBeFirst },,
{ text: 'xxx' },
{ text: 'yyy' },
{ text: 'zzz' }];
[edit: in actual fact I need to sort by more fields, so the actual sort will look more like the code below]
const array = [
{ text: 'xxx', day: 'monday', hour: '12' },
{ text: shouldBeFirst, day: 'tuesday', hour: '12' },
{ text: 'yyy', day: 'wednesday', hour: '12' },
{ text: shouldBeSecond, day: 'thursday', hour: '12'},
{ text: 'zzz', day: 'friday', hour: '12' }];
const ordered = orderBy(array, ['day', 'hour', 'text'], ['asc', 'asc', 'asc']);
Upvotes: 0
Views: 634
Reputation: 29090
It's indeed possible to use orderBy
:
You can do that using orderBy
by supplying a function for the comparison.
const shouldBeFirst = 'My message\r\n\r\nshould consist of A A A A some text';
const shouldBeSecond= 'My message\r\n\r\nshould consist of \r\n\r\n some text';
const array = [
{ text: 'xxx' },
{ text: shouldBeFirst },
{ text: 'yyy' },
{ text: shouldBeSecond},
{ text: 'zzz' }];
const ordered = _.orderBy(array, item => item.text.replace(/\s+/g, " "));
console.log(ordered)
<script src="https://cdn.jsdelivr.net/npm/[email protected]/lodash.min.js"></script>
The replacement can be adjusted, if needed - this is just to illustrate how it can be defined. Multiple criteria can still be passed in as an array
const shouldBeFirst = 'My message\r\n\r\nshould consist of A A A A some text';
const shouldBeSecond= 'My message\r\n\r\nshould consist of \r\n\r\n some text';
const array = [
{ text: 'xxx', value: 2 },
{ text: 'xxx', value: 1 },
{ text: shouldBeFirst },
{ text: 'yyy', value: 42 },
{ text: 'yyy', value: 12 },
{ text: shouldBeSecond},
{ text: 'zzz', value: 7 }];
//separating criteria for better readability
const criteria1 = item => item.text.replace(/\s+/g, " ");
const criteria2 = 'value'; //you can still pick by property name
//order by sanitized values of the text property first, followed by the value property
const ordered = _.orderBy(array, [criteria1, criteria2]);
console.log(ordered);
<script src="https://cdn.jsdelivr.net/npm/[email protected]/lodash.min.js"></script>
Upvotes: 1
Reputation: 21
Use _.sortBy
instead. You can map the values before ordering:
const ordered = _.sortBy(array, arrayItem => arrayItem.text.replace(/\W+/g, " "));
That /\W+/g
is a regex that removes all non-alphanumeric characters from the array item before comparing it.
And, if you'd like to sort by multiple values:
const ordered = _(array).chain()
.sortBy(arrayItem => arrayItem.day)
.sortBy(arrayItem => arrayItem.hour)
.sortBy(arrayItem => arrayItem.text.replace(/\W+/g, " "))
.value();
But, this will sort weekday alphabetically instead of by order in the week - you can always use the moment
library to get the index of the weekday and return that instead.
Upvotes: 1