rozza
rozza

Reputation: 1016

How to ignore new lines in lodash orderBy

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

Answers (2)

VLAZ
VLAZ

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

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

Related Questions