question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Issue sorting columns containing the same value when browsers have implemented an unstable `Array.prototype.sort(comparefn)`

See original GitHub issue

The property of a sorting algorithm that leaves elements that compare as equal in their original list order is called stability. The JavaScript spec specifically allows for implementations to use unstable sort algorithms; no version of Chrome adopts a stable sorting implementation.

The sort is not necessarily stable (that is, elements that compare equal do not necessarily remain in their original order).

It is possible to get a stable sorting from a non-stable sort function. Before sorting you get the position of all the elements. In your sort condition, if both elements are equal, then you sort by the position.


Below is a modified initSort() solving the issue described above - would you be interested in a PR for this change?

if (!Object.keys) {
    Object.keys = function(obj) {
        var keys = [];

        for (var i in obj) {
            if (obj.hasOwnProperty(i)) {
                keys.push(i);
            }
        }

        return keys;
    };
}

BootstrapTable.prototype.initSort = function () {
    var that = this,
        name = this.options.sortName,
        order = this.options.sortOrder === 'desc' ? -1 : 1,
        index = $.inArray(this.options.sortName, this.header.fields),
        length = Object.keys(this.data).length;

    // Add current position to data object in order to enable a stable sort
    // for times when values are compared as equal
    for (var key in this.data) {
        if (this.data.hasOwnProperty(key)) {
            // Save position
            this.data[key].position = key;
        }
    }

    if (index !== -1) {
        this.data.sort(function (a, b) {
            if (that.header.sortNames[index]) {
                name = that.header.sortNames[index];
            }
            var aa = getItemField(a, name),
                bb = getItemField(b, name),
                value = calculateObjectValue(that.header, that.header.sorters[index], [aa, bb]);

            if (value !== undefined) {
                return order * value;
            }

            // Fix #161: undefined or null string sort bug.
            if (aa === undefined || aa === null) {
                aa = '';
            }
            if (bb === undefined || bb === null) {
                bb = '';
            }

            // Found to be equal
            if (aa === bb) {
                    var aa_position = getItemField(a, 'position'),
                        bb_position = getItemField(b, 'position');

                if (order == 1) {
                    aa = (length - aa_position),
                    bb = (length - bb_position);
                } else {
                    aa = aa_position,
                    bb = bb_position;
                }
            }

            // If both values are numeric, do a numeric comparison
            if ($.isNumeric(aa) && $.isNumeric(bb)) {
                // Convert numerical values form string to float.
                aa = parseFloat(aa);
                bb = parseFloat(bb);
                if (aa < bb) {
                    return order * -1;
                }
                return order;
            }

            // If value is not a string, convert to string
            if (typeof aa !== 'string') {
                aa = aa.toString();
            }

            if (aa.localeCompare(bb) === -1) {
                return order * -1;
            }

            return order;
        });
    }
};

Issue Analytics

  • State:closed
  • Created 8 years ago
  • Comments:9 (7 by maintainers)

github_iconTop GitHub Comments

1reaction
djhvscfcommented, Feb 29, 2016

I think this is an important fix for our plugin

0reactions
fvaletascommented, Oct 5, 2017

If a custom sorter is set on a column the fix doesn’t work. if (value !== undefined) { return order * value; } doesn’t handle the equality problem

Read more comments on GitHub >

github_iconTop Results From Across the Web

Array.prototype.sort(compareFn) works different in browsers?
A stable sorting algorithm returns equal list items in the same order as they appear originally, whereas an unstable sorting algorithm does not....
Read more >
Implement a stable sorting algorithm #14412 - GitHub
The user can't just click on two columns in order and expect the first column to still be sorted for any given value...
Read more >
Array.prototype.sort() - JavaScript - MDN Web Docs
The sort() method sorts the elements of an array in place and returns the reference to the same array, now sorted. The default...
Read more >
Sorting in JavaScript: Handling Google Chrome's Unstable Sort
That's called a "stable" sort. Now, the problem with the Array.prototype.sort method is that different browsers implement it differently.
Read more >
90 - V8 doesn't stable sort - Monorail
I think it's absolutely unacceptable that sorting is unstable merely due to the size of the array. I have no problem with v8...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found