简体   繁体   English

按两个数值字段对 Javascript 数组进行排序

[英]sort Javascript array by two numeric fields

grouperArray.sort(function (a, b) {
    var aSize = a.gsize;
    var bSize = b.gsize;
    var aLow = a.glow;
    var bLow = b.glow;
    console.log(aLow + " | " + bLow);      
    return (aSize < bSize) ? -1 : (aSize > bSize) ? 1 : 0;
});

This code sorts the array by gsize , smallest to largest.此代码按gsize对数组进行排序,从小到大。

How would I change it to sort first by gsize and then by glow ?我将如何将其更改为gsize排序,然后按glow排序?

grouperArray.sort(function (a, b) {   
    return a.gsize - b.gsize || a.glow - b.glow;
});

shorter version较短的版本

grouperArray.sort(function (a, b) {
    var aSize = a.gsize;
    var bSize = b.gsize;
    var aLow = a.glow;
    var bLow = b.glow;
    console.log(aLow + " | " + bLow);

    if(aSize == bSize)
    {
        return (aLow < bLow) ? -1 : (aLow > bLow) ? 1 : 0;
    }
    else
    {
        return (aSize < bSize) ? -1 : 1;
    }
});
grouperArray.sort((a, b) => a.gsize - b.gsize || a.glow - b.glow);

Even shorter version using arrow syntax!使用箭头语法的更短版本!

I realize this was asked some time ago, but I thought I would add my solution.我意识到这是前一段时间提出的,但我想我会添加我的解决方案。

This function generates sort methods dynamically.这个 function 动态生成排序方法。 simply supply each sortable child property name, prepended with +/- to indicate ascending or descending order.只需提供每个可排序的子属性名称,前面加上 +/- 以指示升序或降序。 Super re-usable, and it doesn't need to know anything about the data structure you've put together.超级可重用,它不需要知道任何关于你放在一起的数据结构。 Could be made idiot proof - but doesn't seem necessary.可以证明是白痴-但似乎没有必要。

function getSortMethod(){
    var _args = Array.prototype.slice.call(arguments);
    return function(a, b){
        for(var x in _args){
            var ax = a[_args[x].substring(1)];
            var bx = b[_args[x].substring(1)];
            var cx;

            ax = typeof ax == "string" ? ax.toLowerCase() : ax / 1;
            bx = typeof bx == "string" ? bx.toLowerCase() : bx / 1;

            if(_args[x].substring(0,1) == "-"){cx = ax; ax = bx; bx = cx;}
            if(ax != bx){return ax < bx ? -1 : 1;}
        }
    }
}

example usage:示例用法:

items.sort(getSortMethod('-price', '+priority', '+name')); items.sort(getSortMethod('-price', '+priority', '+name'));

this would sort items with lowest price first, with ties going to the item with the highest priority .这将首先对price最低的items进行排序,并priority排序最高的商品。 further ties are broken by the item name项目name打破了进一步的联系

where items is an array like:其中 items 是一个数组,例如:

var items = [
    { name: "z - test item", price: "99.99", priority: 0, reviews: 309, rating: 2 },
    { name: "z - test item", price: "1.99", priority: 0, reviews: 11, rating: 0.5 },
    { name: "y - test item", price: "99.99", priority: 1, reviews: 99, rating: 1 },
    { name: "y - test item", price: "0", priority: 1, reviews: 394, rating: 3.5 },
    { name: "x - test item", price: "0", priority: 2, reviews: 249, rating: 0.5 } ...
];

live demo: http://gregtaff.com/misc/multi_field_sort/现场演示: http://gregtaff.com/misc/multi_field_sort/

EDIT: Fixed issue with Chrome.编辑:修复了 Chrome 的问题。

I expect the ternary operator ((aSize < bSize)? -1: (aSize > bSize)? 1: 0;) has you confused.我希望三元运算符((aSize < bSize)? -1: (aSize > bSize)? 1: 0;)让你感到困惑。 You should check out the link to understand it better.您应该查看链接以更好地理解它。

Until then, here's your code blown out into full if/else.在那之前,你的代码会在 if/else 中被爆满。

grouperArray.sort(function (a, b) {
    if (a.gsize < b.gsize)
    {
        return -1;
    }
    else if (a.gsize > b.gsize)
    {
        return 1;
    }
    else
    {
        if (a.glow < b.glow)
        {
            return -1;
        }
        else if (a.glow > b.glow)
        {
            return 1;
        }
        return 0;
    }
});

Here's an implementation for those who may want something more generic that would work with any number of fields.对于那些可能想要更通用的东西来处理任意数量的字段的人来说,这是一个实现。

Array.prototype.sortBy = function (propertyName, sortDirection) {

    var sortArguments = arguments;
    this.sort(function (objA, objB) {

        var result = 0;
        for (var argIndex = 0; argIndex < sortArguments.length && result === 0; argIndex += 2) {

            var propertyName = sortArguments[argIndex];
            result = (objA[propertyName] < objB[propertyName]) ? -1 : (objA[propertyName] > objB[propertyName]) ? 1 : 0;

            //Reverse if sort order is false (DESC)
            result *= !sortArguments[argIndex + 1] ? 1 : -1;
        }
        return result;
    });

}

Basically, you may specify any number of property name / sort direction:基本上,您可以指定任意数量的属性名称/排序方向:

var arr = [{
  LastName: "Doe",
  FirstName: "John",
  Age: 28
}, {
  LastName: "Doe",
  FirstName: "Jane",
  Age: 28
}, {
  LastName: "Foo",
  FirstName: "John",
  Age: 30
}];

arr.sortBy("LastName", true, "FirstName", true, "Age", false);
//Will return Jane Doe / John Doe / John Foo

arr.sortBy("Age", false, "LastName", true, "FirstName", false);
//Will return John Foo / John Doe / Jane Doe

Here is an implementation that uses recursion to sort by any number of sort fields from 1 to infinite.这是一个实现,它使用递归按从 1 到无限的任意数量的排序字段进行排序。 You pass it a results array which is an array of result objects to sort, and a sorts array which is an array of sort objects defining the sort.您向它传递一个 results 数组,它是一个要排序的结果对象数组,以及一个 sorts 数组,它是一个定义排序的排序对象数组。 Each sort object must have a "select" key for the key name that it sorts by and an "order" key which is a string indicating "ascending" or "descending".每个排序 object 必须有一个“选择”键作为它排序的键名和一个“顺序”键,它是一个指示“升序”或“降序”的字符串。

sortMultiCompare = (a, b, sorts) => {
    let select = sorts[0].select
    let order = sorts[0].order
    if (a[select] < b[select]) {
        return order == 'ascending' ? -1 : 1
    } 
    if (a[select] > b[select]) {
        return order == 'ascending' ? 1 : -1
    }
    if(sorts.length > 1) {
        let remainingSorts = sorts.slice(1)
        return this.sortMultiCompare(a, b, remainingSorts)
    }
    return 0
}

sortResults = (results, sorts) => {
    return results.sort((a, b) => {
        return this.sortMultiCompare(a, b, sorts)
    })
}

// example inputs
const results = [
    {
        "LastName": "Doe",
        "FirstName": "John",
        "MiddleName": "Bill"
    },
    {
        "LastName": "Doe",
        "FirstName": "Jane",
        "MiddleName": "Bill"
    },
    {
        "LastName": "Johnson",
        "FirstName": "Kevin",
        "MiddleName": "Bill"
    }
]

const sorts = [
    {
        "select": "LastName",
        "order": "ascending"
    },
    {
        "select": "FirstName",
        "order": "ascending"
    },
    {
        "select": "MiddleName",
        "order": "ascending"
    }    
]

// call the function like this:
let sortedResults = sortResults(results, sorts)
grouperArray.sort(function (a, b) {
  var aSize = a.gsize;
  var bSize = b.gsize;
  var aLow = a.glow;
  var bLow = b.glow;
  console.log(aLow + " | " + bLow);      
  return (aSize < bSize) ? -1 : (aSize > bSize) ? 1 : ( (aLow < bLow ) ? -1 : (aLow > bLow ) ? 1 : 0 );
});
grouperArray.sort(function (a, b) {
     var aSize = a.gsize;     
     var bSize = b.gsize;     
     var aLow = a.glow;
     var bLow = b.glow;
     console.log(aLow + " | " + bLow);
     return (aSize < bSize) ? -1 : (aSize > bSize) ? 1 : (aLow < bLow) ? -1 : (aLow > bLow) ? 1 : 0); }); 

A dynamic way to do that with MULTIPLE keys:使用 MULTIPLE 键的动态方法:

  • filter unique values from each col/key of sort从排序的每个列/键中过滤唯一值
  • put in order or reverse it整理或颠倒它
  • add weights width zeropad for each object based on indexOf(value) keys values根据 indexOf(value) 键值为每个 object 添加权重宽度 zeropad
  • sort using caclutated weights使用计算权重排序

在此处输入图像描述

Object.defineProperty(Array.prototype, 'orderBy', {
value: function(sorts) { 
    sorts.map(sort => {            
        sort.uniques = Array.from(
            new Set(this.map(obj => obj[sort.key]))
        );

        sort.uniques = sort.uniques.sort((a, b) => {
            if (typeof a == 'string') {
                return sort.inverse ? b.localeCompare(a) : a.localeCompare(b);
            }
            else if (typeof a == 'number') {
                return sort.inverse ? (a < b) : (a > b ? 1 : 0);
            }
            else if (typeof a == 'boolean') {
                let x = sort.inverse ? (a === b) ? 0 : a? -1 : 1 : (a === b) ? 0 : a? 1 : -1;
                return x;
            }
            return 0;
        });
    });

    const weightOfObject = (obj) => {
        let weight = "";
        sorts.map(sort => {
            let zeropad = `${sort.uniques.length}`.length;
            weight += sort.uniques.indexOf(obj[sort.key]).toString().padStart(zeropad, '0');
        });
        //obj.weight = weight; // if you need to see weights
        return weight;
    }

    this.sort((a, b) => {
        return weightOfObject(a).localeCompare( weightOfObject(b) );
    });

    return this;
}
});

Use:利用:

// works with string, number and boolean
let sortered = your_array.orderBy([
    {key: "type", inverse: false}, 
    {key: "title", inverse: false},
    {key: "spot", inverse: false},
    {key: "internal", inverse: true}
]);

在此处输入图像描述

This is what I use这就是我使用的

function sort(a, b) {
    var _a = "".concat(a.size, a.glow);
    var _b = "".concat(b.size, b.glow);
    return _a < _b;
}

concat the two items as a string and they will be sorted by a string value.将这两个项目连接为一个字符串,它们将按字符串值排序。 If you want you could wrap _a and _b with parseInt to compare them as numbers if you know they will be numerical.如果您愿意,可以用 parseInt 包装 _a 和 _b 以将它们作为数字进行比较,如果您知道它们将是数字的话。

Here is the solution for the case, when you have a priority sort key, which might not exist in some particular items, so you have to sort by fallback keys.这是这种情况的解决方案,当您有优先排序键时,某些特定项目中可能不存在该优先排序键,因此您必须按后备键排序。

An input data example ( id2 is priority sort key):输入数据示例( id2是优先排序键):

const arr = [
    {id: 1},
    {id: 2, id2: 3},
    {id: 4},
    {id: 3},
    {id: 10, id2: 2},
    {id: 7},
    {id: 6, id2: 1},
    {id: 5},
    {id: 9, id2: 2},
    {id: 8},
];

And the output should be: output 应该是:

[ { id: 6, id2: 1 },
  { id: 9, id2: 2 },
  { id: 10, id2: 2 },
  { id: 2, id2: 3 },
  { id: 1 },
  { id: 3 },
  { id: 4 },
  { id: 5 },
  { id: 7 },
  { id: 8 } ]

The comparator function will be like:比较器 function 将类似于:

arr.sort((a,b) => {
  if(a.id2 || b.id2) {
    if(a.id2 && b.id2) {
      if(a.id2 === b.id2) {
        return a.id - b.id;
      }
      return a.id2 - b.id2;
    }
    return a.id2 ? -1 : 1;
  }
  return a.id - b.id
});

PS In case if .id of .id2 can be zeros, consider to use typeof . PS 如果.id2.id可以为零,请考虑使用typeof

Let's simplify.让我们简化一下。

Say you have an array of arrays:假设你有一个 arrays 数组:

let tmp = [
    [0, 1],
    [2, 1],
    [1, 1],
    [0, 0],
    [2, 0],
    [1, 0],
    [0, 2],
    [2, 2],
    [1, 2],
]

Executing:执行:

tmp.sort((a, b) => {
    if (a[1] != b[1])
        return a[1] - b[1];
    else
        return a[0] - b[0];
})

Will yield:将产生:

[
    [0, 0],
    [1, 0],
    [2, 0],
    [0, 1],
    [1, 1],
    [2, 1],
    [0, 2],
    [1, 2],
    [2, 2]
]
grouperArray.sort(function (a, b) {
    var aSize = a.gsize;
    var bSize = b.gsize;
    if (aSize !== aSize)
        return aSize - bSize;
    return a.glow - b.glow;
});

not tested, but I think that should work.未经测试,但我认为应该可以。

grouperArray.sort(
  function(a,b){return a.gsize == b.gsize ? a.glow - b.glow : a.gsize - b.gsize}
);

In my case, i sort notification list by param 'important' and by 'date'就我而言,我按参数“重要”和“日期”对通知列表进行排序

  • step 1: i filter notifications by 'important' and unImportant第 1 步:我按“重要”和“不重要”过滤通知

    let importantNotifications = notifications.filter( (notification) => notification.isImportant); let unImportantNotifications = notifications.filter( (notification) =>.notification;isImportant);
  • step 2: i sort them by date第 2 步:我按日期对它们进行排序

     sortByDate = (notifications) => { return notifications.sort((notificationOne, notificationTwo) => { return notificationOne.date - notificationTwo.date; }); };
  • step 3: merge them第 3 步:合并它们

    [...this.sortByDate(importantNotifications), ...this.sortByDate(unImportantNotifications), ];

If you're happy to use the new tidy.js package you can achieve this with如果您乐于使用新的tidy.js package ,您可以使用

tidy(input_array,
  arrange(['var1', desc('var2')])
);

Besides the other answers here I got inconsistent data on my arrays where 1 wanted a primary ASC sort on field x and a secondary DESC sort on field y.除了这里的其他答案之外,我的 arrays 上的数据不一致,其中 1 想要在字段 x 上进行主要 ASC 排序,在字段 y 上进行次要 DESC 排序。
The solution is in giving the primary sort more importance by multiplying the number with lets say 1000000000解决方案是通过将数字乘以 1000000000 来赋予主要排序更多的重要性

arrayOfObjects.sort((a, b) => {
    return (
        // Multiply by a high number to the most important sort, that makes them heavier than the second sort

        // First sort ASC (notice the - minus in the end instead of the || in other answers !)
        (a.paramX * 1000000000) -
        (b.paramX * 1000000000) -

        // Second sort DESC (switch them if you want ASC too)
        (a.paramY - b.paramY)
    )
})

for sorting on multiple dates on the object it is this:在 object 上对多个日期进行排序是这样的:

// param date1 ASC and param date2 DESC
arrayOfObjects.sort((a, b) => {
    return (
        (a.date1.getTime() * 1000000000) -
        (b.date1.getTime() * 1000000000) -
        (a.date2.getTime() - b.date2.getTime())
    )
})
var items = [
    { name: "z - test item", price: "99.99", priority: 0, reviews: 309, rating: 2 },
    { name: "z - test item", price: "1.99", priority: 0, reviews: 11, rating: 0.5 },
    { name: "y - test item", price: "99.99", priority: 1, reviews: 99, rating: 1 },
    { name: "y - test item", price: "0", priority: 1, reviews: 394, rating: 3.5 },
    { name: "x - test item", price: "0", priority: 2, reviews: 249, rating: 0.5 }];

items.sort(function (a, b) {
    var nameA = a.name.toUpperCase(); 
    var nameB = b.name.toUpperCase();   
    var nameC = a.price.toUpperCase(); 
    var nameD = b.price.toUpperCase(); 

    if (nameA < nameB) {
            return -1;
        }
        if (nameA > nameB || nameC > nameD) {
            return 1;
        }

        // names must be equal
        return 0;
    });`

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM