1

I am trying to sort an Array using a String field and it is sorting it wrongly.

My code looks like this.

 let tempWEArray = [
    {
      "from" : "09/2005",
      "to" : "11/2006"
    }, 
    {
      "from" : "09/2006",
      "to" : "11/2007"
    }, 
    {
      "from" : "12/2007",
      "to" : "01/2009"
    }, 
    {
      "from" : "01/2009",
      "to" : "12/2012"
    }, 
    {
      "from" : "01/2013",
      "to" : "03/2018"
    }]

    function sortBy(prop){
        return function(a,b){
            if( a[prop] < b[prop])
            {
                return -1;
            }
            else if( a[prop] > b[prop] )
            {
                return 1;
            }
            return 0;
        }
    }
    
    console.log(tempWEArray.sort(sortBy("to")))

The output obtained is like below.

0: Object { from: "12/2007", to: "01/2009" }
​
1: Object { from: "01/2013", to: "03/2018" }
​
2: Object { from: "09/2005", to: "11/2006" }
​
3: Object { from: "09/2006", to: "11/2007" }
​
4: Object { from: "01/2009", to: "12/2012" }

The Array isn't getting sorted properly as you can see above. One field is misplaced. Am i doing something wrong?

All the below answers work, I've selected the Answer which I have implemented. Thanks everyone.

4
  • 1
    Using < and > to compare strings doesn't make much sense, try localeCompare instead Commented Dec 28, 2018 at 10:28
  • 1
    The object is sorted alphabetically, exactly as you told it to sort. Commented Dec 28, 2018 at 10:31
  • @CertainPerformance I was referring to this stackoverflow.com/questions/1129216/… when i wrote that function. Will localeCompare sort it out? Commented Dec 28, 2018 at 10:33
  • @connexo Oh! My bad. How do i make sure it sorts it properly? Commented Dec 28, 2018 at 10:34

5 Answers 5

3

You could first parse those dates and then you can use - to sort them.

let arr = [{"from":"09/2005","to":"11/2006"},{"from":"09/2006","to":"11/2007"},{"from":"12/2007","to":"01/2009"},{"from":"01/2009","to":"12/2012"},{"from":"01/2013","to":"03/2018"}]

const parse = str => {
  let date = new Date;
  let [month, year] = str.split('/')
  date.setYear(year);
  date.setMonth(+month - 1)
  return date;
}

const sortBy = prop => (a, b) => {
  return parse(b[prop]) - parse(a[prop])
}

arr.sort(sortBy('to'))
console.log(arr)

Sign up to request clarification or add additional context in comments.

2 Comments

setMonth() monthValue An integer between 0 and 11, representing the months January through December.
@rckrd Updated it.
2

Convert it to a date in your sort and it'll work as you intended.

seperate each component of the date string and reverse it

const dateArray = b[prop].split("/").reverse()

Use the spread operator to create a timestamp with Date.UTC and then use new Date to create a date.

new Date(Date.UTC(...dateArray))

Then use the - between two dates to find which one is bigger in a sort function.

Some example:

const res = new Date(Date.UTC(..."11/2006".split("/").reverse()))

console.log(res);

Full solution:

let tempWEArray = [{"from":"09/2005","to":"11/2006"},{"from":"09/2006","to":"11/2007"},{"from":"12/2007","to": "01/2009"},{"from":"01/2009","to": "12/2012"},{"from":"01/2013","to": "03/2018"}]

function sortBy(prop) {
  return function(a, b) {
  
    const dateArr1 = a[prop].split("/").reverse();
    const dateArr2 = b[prop].split("/").reverse();
    
    //make sure months are between 0 and 11
    //can be skipped if this is already ensured.
    dateArr1[1]--;
    dateArr2[1]--;

    return new Date(Date.UTC(...dateArr2)) - new Date(Date.UTC(...dateArr1));
  }
}

console.log(tempWEArray.sort(sortBy("to")))

2 Comments

new Date(Date.UTC(..."11/2006".split("/").reverse())) => Dec 2016 . Should be Nov 2016
Of course. But is a potential bug, if the same method is used to parse dates in another scenario.
2

You can use moment.js for date camparation. example:

let tempWEArray = [
{
  "from" : "09/2005",
  "to" : "11/2006"
}, 
{
  "from" : "09/2006",
  "to" : "11/2007"
}, 
{
  "from" : "12/2007",
  "to" : "01/2009"
}, 
{
  "from" : "01/2009",
  "to" : "12/2012"
}, 
{
  "from" : "01/2013",
  "to" : "03/2018"
}];

const sortedArray = tempWEArray.sort(
(first, second)  => moment(first.to, 'MM/YYYY')
                    .isSameOrAfter(moment(second.to, 'MM/YYYY')));
console.log(sortedArray);
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.23.0/moment.min.js"></script>

Comments

2
function sortBy(prop) {
  return function(a, b) {
const dateArray = b[prop].split("/").reverse()
console.log()
  }
}

Comments

1

You could replace the date pattern with a comparable string and omit if the string has not a date pattern.

function sortBy(prop){
    return function(a,b){
        var valueA = a[prop].replace(/^(\d{2})\/(\d{4})$/, '$2-$1'),
            valueB = b[prop].replace(/^(\d{2})\/(\d{4})$/, '$2-$1');

        return valueA.localeCompare(valueB);
    }
}

var tempWEArray = [{ from: "09/2005", to: "11/2006" }, { from: "09/2006", to: "11/2007" }, { from: "12/2007", to: "01/2009" }, { from: "01/2009", to: "12/2012" }, { from: "01/2013", to: "03/2018" }]
   
console.log(tempWEArray.sort(sortBy("to")))
.as-console-wrapper { max-height: 100% !important; top: 0; }

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.