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.

Nithin
  • 1,387
  • 4
  • 19
  • 48
  • 1
    Using `<` and `>` to compare *strings* doesn't make much sense, try `localeCompare` instead – CertainPerformance Dec 28 '18 at 10:28
  • 1
    The object is sorted alphabetically, exactly as you told it to sort. – connexo Dec 28 '18 at 10:31
  • @CertainPerformance I was referring to this https://stackoverflow.com/questions/1129216/sort-array-of-objects-by-string-property-value when i wrote that function. Will `localeCompare` sort it out? – Nithin Dec 28 '18 at 10:33
  • @connexo Oh! My bad. How do i make sure it sorts it properly? – Nithin Dec 28 '18 at 10:34

5 Answers5

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)
Nenad Vracar
  • 118,580
  • 15
  • 151
  • 176
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")))
kemicofa ghost
  • 16,349
  • 8
  • 82
  • 131
  • `new Date(Date.UTC(..."11/2006".split("/").reverse()))` => **Dec 2016** . Should be **Nov 2016** – rckrd Dec 28 '18 at 10:51
  • 1
    Of course. But is a potential bug, if the same method is used to parse dates in another scenario. – rckrd Dec 28 '18 at 10:59
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>
Igor Litvinovich
  • 2,436
  • 15
  • 23
2
function sortBy(prop) {
  return function(a, b) {
const dateArray = b[prop].split("/").reverse()
console.log()
  }
}
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; }
Nina Scholz
  • 376,160
  • 25
  • 347
  • 392