1

I am trying to sort the array of objects based on change property.

Below is the sort function, the strange part is the price when below 100 it's not getting sorted properly. I want the array of objects to be sorted by asc or desc order by either change or name.

const data = [{
    "id": 74368,
    "account": "Gerald Wehner",
    "change": "186.00"
  },
  {
    "id": 55998,
    "account": "Augusta Koelpin",
    "change": "277.00"
  },
  {
    "id": 3044,
    "account": "Austyn Bradtke",
    "change": "473.00"
  },
  {
    "id": 50305,
    "account": "Lesly Boyer",
    "change": "56.00"
  },
  {
    "id": 20324,
    "account": "Marietta Lynch",
    "change": "707.00"
  },
  {
    "id": 40233,
    "account": "Eriberto Haley",
    "change": "923.00"
  }
];

sort = (arr, field, order, cond) => {
  const fn = cond ?
    function(x) {
      return cond(x[field])
    } :
    function(x) {
      return x[field]
    };

  order = !order ? 1 : -1;

  return arr.sort(function(a, b) {
    return a = fn(a), b = fn(b), order * ((a > b) - (b > a));
  })
}

console.log(sort(data, 'change', true, false))
thingEvery
  • 3,368
  • 1
  • 19
  • 25
Thalapathy
  • 127
  • 1
  • 1
  • 12
  • 1
    If you want to sort numerically you need to convert the strings to numbers with something like `parseFloat()` i.e. `parseFloat(b.change) - parseFloat(a.change)` – Mark Jan 27 '20 at 00:22

2 Answers2

2

You're comparing the values as text instead of numbers.

const data = [{
    "id": 74368,
    "account": "Gerald Wehner",
    "change": "186.00"
  },
  {
    "id": 55998,
    "account": "Augusta Koelpin",
    "change": "277.00"
  },
  {
    "id": 3044,
    "account": "Austyn Bradtke",
    "change": "473.00"
  },
  {
    "id": 50305,
    "account": "Lesly Boyer",
    "change": "56.00"
  },
  {
    "id": 20324,
    "account": "Marietta Lynch",
    "change": "707.00"
  },
  {
    "id": 40233,
    "account": "Eriberto Haley",
    "change": "923.00"
  }
];

sort = (arr, field, order, cond) => {
  const fn = cond ?
    function(x) {
      return Number(cond(x[field]));
    } :
    function(x) {
      return Number(x[field]);
    };

  order = !order ? 1 : -1;

  return arr.sort(function(a, b) {
    return a = fn(a), b = fn(b), order * ((a > b) - (b > a));
  })
}

console.log(sort(data, 'change', true, false))
thingEvery
  • 3,368
  • 1
  • 19
  • 25
  • what if the passed value is not a number? Is there a way to determine it dynamically from the array of objects itself... – Thalapathy Jan 27 '20 at 00:33
  • @Thalapathy the point is, the passed value _isn't_ a number in your case. It's a numeric _string_. That's why the values were being sorted lexicographically instead of numerically. You need to know what the format of your input is in order to sort it properly. Don't fall for the "one size fits all" mentality. – Patrick Roberts Jan 27 '20 at 00:36
  • 1
    @Thalapathy You could check if the input is a number using a regex, then sort it accordingly. e.g. `if (x.match(/^[0-9.]*$/)) {sort as number} else {sort as text}` – thingEvery Jan 27 '20 at 14:08
1

Note that, in the case of strings like "account" this sorts by first name, then last name:

const data=[{id:74368,account:"Gerald Wehner",change:"186.00"},{id:55998,account:"Augusta Koelpin",change:"277.00"},{id:3044,account:"Austyn Bradtke",change:"473.00"},{id:50305,account:"Lesly Boyer",change:"56.00"},{id:20324,account:"Marietta Lynch",change:"707.00"},{id:40233,account:"Eriberto Haley",change:"923.00"}]

function sortData(dir, prop){
    return data.sort((a,b) => {
        let x = dir === "ASC" ? a : b
        let y = dir === "ASC" ? b : a
    
        if(isNaN(data[0][prop])){
            return x[prop].localeCompare(y[prop])
        }else{
            return x[prop] - y[prop] 
        }
    })
}

console.log(sortData("ASC", "change"))

Update

Added functionality for new format (see comments)

const data=[{id:74368,account:"Gerald Wehner",change:" GeraldWehner - 186"},{id:55998,account:"AugustaKoelpin",change:"AugustaKoelpin - 999"}]

function sortData(dir, prop){
    return data.sort((a,b) => {
        let x = dir === "ASC" ? a : b
        let y = dir === "ASC" ? b : a
    
        let exProp = data[0][prop]
        if(isNaN(exProp)){
            if( exProp.indexOf("-") > -1 && !isNaN( exProp.split("-")[1].trim() ) ){
                let xTest = x[prop].split("-")[1].trim()
                let yTest = y[prop].split("-")[1].trim()
                
                return xTest - yTest
            }
            
            return x[prop].localeCompare(y[prop])
        }else{
            return x[prop] - y[prop] 
        }
    })
}

console.log(sortData("ASC", "change"))
Community
  • 1
  • 1
symlink
  • 11,984
  • 7
  • 29
  • 50