Home > Enterprise >  How to sort Object array based on property
How to sort Object array based on property

Time:11-05

I have a requirement to sort a object array based on frozenEdge property. If property value is start we should move item to top and property value is end we have to move item to bottom. Item which doesn't have field property are invalid so there position should remain as it ,In below array for example first item is invalid so we should not reorder.

I have tried a sample program which work in firefox but failing in chrome I am looking for a solution which can work in chrome, safari and firefox

Actual Array

[{
  "style": "width: 10px; text-align: center",
  "className": "oj-sm-only-hide table",
  "headerClassName": "Sample"
}, {
  "headerText": "Fee Description",
  "field": "Description"
}, {
  "headerText": "Amount",
  "field": "FeeAmount",
  "frozenEdge": "start"
}, {
  "headerText": "Currency",
  "field": "CurrencyCode",
  "frozenEdge": "start"
}, {
  "headerText": "Status",
  "field": "FeeStatus",
}, {
  "headerText": "Department",
  "field": "DepartmentDescription"
}, {
  "headerText": "Assessed Date",
  "field": "AssessedDate",
  "frozenEdge": "end"
}, {
  "headerText": "Payment Date",
  "field": "PaymentDate"
}, {
  "headerText": "Paid By",
  "field": "PaidBy",
  "frozenEdge": "end"
}, {
  "headerText": "Invoice",
  "field": "Invoice"
}, {
  "headerClassName": "table-header table-row-botton",
  "className": "table-row-botton"
}]

Expected Output

[{
  "style": "width: 10px; text-align: center",
  "className": "oj-sm-only-hide table",
  "headerClassName": "Sample"
}, {
  "headerText": "Amount",
  "field": "FeeAmount",
  "frozenEdge": "start"
}, {
  "headerText": "Currency",
  "field": "CurrencyCode",
  "frozenEdge": "start"
}, {
  "headerText": "Fee Description",
  "field": "Description"
}, {
  "headerText": "Status",
  "field": "FeeStatus",
}, {
  "headerText": "Department",
  "field": "DepartmentDescription"
}, {
  "headerText": "Payment Date",
  "field": "PaymentDate"
}, {
  "headerText": "Invoice",
  "field": "Invoice"
}, {
  "headerText": "Assessed Date",
  "field": "AssessedDate",
  "frozenEdge": "end"
}, {
  "headerText": "Paid By",
  "field": "PaidBy",
  "frozenEdge": "end"
}, {
  "headerClassName": "table-header table-row-botton",
  "className": "table-row-botton"
}]

Working code for Firefox:

function isValidColumn(column, ignoreFR) {
  var retVal = true;
  if (!column.hasOwnProperty('field')) {
    return false;
  }
  return retVal;
}

var array = [{
  "style": "width: 10px; text-align: center",
  "className": "oj-sm-only-hide table",
  "headerClassName": "Sample"
}, {
  "headerText": "Fee Description",
  "field": "Description"
}, {
  "headerText": "Amount",
  "field": "FeeAmount",
  "frozenEdge": "start"
}, {
  "headerText": "Currency",
  "field": "CurrencyCode",
  "frozenEdge": "start"
}, {
  "headerText": "Status",
  "field": "FeeStatus",
}, {
  "headerText": "Department",
  "field": "DepartmentDescription"
}, {
  "headerText": "Assessed Date",
  "field": "AssessedDate",
  "frozenEdge": "end"
}, {
  "headerText": "Payment Date",
  "field": "PaymentDate"
}, {
  "headerText": "Paid By",
  "field": "PaidBy",
  "frozenEdge": "end"
}, {
  "headerText": "Invoice",
  "field": "Invoice"
}, {
  "headerClassName": "table-header table-row-botton",
  "className": "table-row-botton"
}];

array.sort(
  function(col1, col2) {
    if (isValidColumn(col1, true) && isValidColumn(col2, true)) {

      if (col2.hasOwnProperty('frozenEdge') &&
        col2.frozenEdge == 'start') {
        return (col2.frozenEdge === 'start' && col1.frozenEdge !== 'start') ? 1 :
          (col1.frozenEdge === 'start') ? -1 : 0;
      } else if (col1.hasOwnProperty('frozenEdge') &&
        col1.frozenEdge == 'end') {
        return (col1.frozenEdge == 'end' && col2.frozenEdge !== 'end') ? 1 :
          (col1.frozenEdge === 'end') ? -1 : 0;
      } else {
        return 0;
      }
    } else {
      return 0;
    }
  }
);

console.log(array);
.as-console-wrapper { top: 0; max-height: 100% !important; }
<iframe name="sif1" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>

CodePudding user response:

You could take an object with the wanted order and check field first.

const
    order = { start: -1, default: 0, end: 1 },
    data = [{ style: "width: 10px; text-align: center", className: "oj-sm-only-hide table", headerClassName: "Sample" }, { headerText: "Fee Description", field: "Description" }, { headerText: "Amount", field: "FeeAmount", frozenEdge: "start" }, { headerText: "Currency", field: "CurrencyCode", frozenEdge: "start" }, { headerText: "Status", field: "FeeStatus" }, { headerText: "Department", field: "DepartmentDescription" }, { headerText: "Assessed Date", field: "AssessedDate", frozenEdge: "end" }, { headerText: "Payment Date", field: "PaymentDate" }, { headerText: "Paid By", field: "PaidBy", frozenEdge: "end" }, { headerText: "Invoice", field: "Invoice" }, { headerClassName: "table-header table-row-botton", className: "table-row-botton" }];

data.sort((a, b) => 
    a.field && b.field &&
    (order[a.frozenEdge] || order.default) - (order[b.frozenEdge] || order.default)
);

console.log(data);
.as-console-wrapper { max-height: 100% !important; top: 0; }
<iframe name="sif2" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>

CodePudding user response:

This should work, if you want items with frozenEdge: "start" on top and frozenEdge: "end" on the bottom:

array.sort((x, y) => {
    if (y.frozenEdge === undefined && x.frozenEdge == undefined) return 0

    if (y.frozenEdge === undefined && x.frozenEdge == "end") return 1
    if (y.frozenEdge === undefined && x.frozenEdge == "start") return -1

    if (y.frozenEdge == "end" && x.frozenEdge == undefined) return -1
    if (y.frozenEdge == "start" && x.frozenEdge == undefined ) return 1
})

Checkout mdn docs on Array.prototype.sort() for more info.

It seems that in your "Expected Output" snippet you actually wanted to keep the first and last elements of the array at their indices before sorting. I'd suggest to pop() and shift() the last and first items respectively, something like this:

const first = array.shift()
const last = array.pop()

array = array.sort( /*...*/ )

array = [first, ...array, last]
  • Related