0

I have an observable array of objects that are used to populate a table with sortable columns.

My sorting function works perfectly and is based on the following simplification:

self.sortTheItems = function () {
    self.items.sort(function (l, r) {
        var rslt = l === r ? 0 : l < r ? -1 : 1;
        return self.sortAscending() ? rslt : -rslt;
    });
}

How could this be changed to always place values of 0 last both for ascending and descending sorting?

e.g. Unsorted values: 3,1,2,2,0,1,3,0

Descending: 3,3,2,2,1,1,0,0

Ascending: 1,1,2,2,3,3,0,0

Drummad
  • 722
  • 1
  • 6
  • 23

2 Answers2

2

I think you just need to make it return 1 if l is zero - see updated script below

self.items.sort(function(l, r) {
  var rslt,
    isAscending = self.sortAscending();

  if (l === r) {
    rslt = 0; // return 0 if they are equal
  } else if (l === 0) {
    if (isAscending) {
      rslt = -1; // return -1 as this is minused below to make positive 1 (moving things to the back)
    } else {
      rslt = 1; // return 1 to force to end;
    }
  } else if (l > r) {
    rslt = 1; // return 1 if l is greater than r
  } else {
    rslt = -1; // return -1 when l is less than r
  }

  return isAscending ? rslt : -rslt;
});
Pete
  • 57,112
  • 28
  • 117
  • 166
  • Thank you for the answer. It seems to be on the right track but with the latest edit I am getting the order: 0,1,2,3,4 for ascending order. – Drummad May 22 '17 at 13:42
  • Ah I forgot if it was ascending it then gets minused again, meaning we need it to be -1 for ascending and 0 - see edit above. You'll probably be able to clean up the ifs a bit, but that is just to give you the idea – Pete May 22 '17 at 14:00
  • Thanks again Pete for taking the time to post a good answer. Your logic has definitely helped me but unfortunately it doesn't seem to work completely for me. – Drummad May 23 '17 at 15:03
  • 1
    No problems, wasn't sure if it would as I don't have a platform to test on and haven't really used knockout, as long as you have found an answer, that's the main goal :) – Pete May 23 '17 at 15:07
1

I believe the main issue, sorting one value always last, has been answered many times before on stack overflow. (example)

To make things more interesting, you might want to explore what knockoutjs can bring to the table.

It might be nice to include a computed sort method and a computed array of sorted items so one checkbox swaps between two methods:

// Wraps a sort method in a pre-check
const sortZeroesLast = sorter => (a, b) => {
  // Check both for `0`
  if (a === 0) return 1;
  if (b === 0) return -1;
  // If none is `0`, we can use our regular sorter
  return sorter(a, b);
};

// Regular sort methods
const sortAscending = (a, b) => (a > b ? 1 : a < b ? -1 : 0);

const sortDescending = (a, b) => (a < b ? 1 : a > b ? -1 : 0);

const VM = function() {
  this.items = ko.observableArray([3, 1, 1, 0, 2, 1, 5]);

  // Determine which sort function to use based on `ascending` setting
  this.ascending = ko.observable(false);

  const sorter = ko.pureComputed(() =>
    sortZeroesLast(this.ascending() ? sortAscending : sortDescending)
  );

  // Create a computed that updates when the items
  // change, or the ascending direction
  this.sortedItems = ko.pureComputed(() => this.items().sort(sorter()));

  this.input = ko.observable(0);
  this.addInput = () => {
    this.items.push(parseFloat(this.input() || 0));
  };
};

ko.applyBindings(new VM());
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>

<label>
  <input type="checkbox" data-bind="checked: ascending">
  Ascending
</label>

<ul data-bind="foreach: sortedItems">
  <li data-bind="text: $data"></li>
</ul>

<input type="number" data-bind="value: input"><button data-bind="click: addInput">add</button>
user3297291
  • 22,592
  • 4
  • 29
  • 45
  • Thanks for this answer, very useful to see a working snippet. I will have to refactor some of the javascript due to our target browsers not supporting ES6 but I will be using your general idea in a less pretty way! – Drummad May 23 '17 at 15:05