从这个最初的问题,我将如何在多个字段应用排序?

使用这种稍作调整的结构,我将如何排序城市(上升)和价格(下降)?

var homes = [
    {"h_id":"3",
     "city":"Dallas",
     "state":"TX",
     "zip":"75201",
     "price":"162500"},
    {"h_id":"4",
     "city":"Bevery Hills",
     "state":"CA",
     "zip":"90210",
     "price":"319250"},
    {"h_id":"6",
     "city":"Dallas",
     "state":"TX",
     "zip":"75000",
     "price":"556699"},
    {"h_id":"5",
     "city":"New York",
     "state":"NY",
     "zip":"00010",
     "price":"962500"}
    ];

我喜欢的事实是,给出的答案提供了一个一般的方法。在我计划使用这段代码的地方,我将不得不对日期以及其他东西进行排序。“启动”对象的能力似乎很方便,如果不是有点麻烦的话。

我试图把这个答案构建成一个很好的通用示例,但我运气不太好。


当前回答

只是另一种选择。考虑使用以下效用函数:

/** Performs comparing of two items by specified properties
 * @param  {Array} props for sorting ['name'], ['value', 'city'], ['-date']
 * to set descending order on object property just add '-' at the begining of property
 */
export const compareBy = (...props) => (a, b) => {
  for (let i = 0; i < props.length; i++) {
    const ascValue = props[i].startsWith('-') ? -1 : 1;
    const prop = props[i].startsWith('-') ? props[i].substr(1) : props[i];
    if (a[prop] !== b[prop]) {
      return a[prop] > b[prop] ? ascValue : -ascValue;
    }
  }
  return 0;
};

用法示例(在您的情况下):

homes.sort(compareBy('city', '-price'));

值得注意的是,这个函数可以更一般化,以便能够使用嵌套属性,如'address '。City '或'style.size。宽度”等。

其他回答

下面这个简单的解决方案怎么样:

const sortCompareByCityPrice = (a, b) => {
    let comparison = 0
    // sort by first criteria
    if (a.city > b.city) {
        comparison = 1
    }
    else if (a.city < b.city) {
        comparison = -1
    }
    // If still 0 then sort by second criteria descending
    if (comparison === 0) {
        if (parseInt(a.price) > parseInt(b.price)) {
            comparison = -1
        }
        else if (parseInt(a.price) < parseInt(b.price)) {
            comparison = 1
        }
    }
    return comparison 
}

基于这个问题javascript排序数组的多个(数字)字段

哇,这里有一些复杂的解。如此复杂,我决定想出一些更简单但也相当强大的东西。在这里;

function sortByPriority(data, priorities) {
  if (priorities.length == 0) {
    return data;
  }

  const nextPriority = priorities[0];
  const remainingPriorities = priorities.slice(1);

  const matched = data.filter(item => item.hasOwnProperty(nextPriority));
  const remainingData = data.filter(item => !item.hasOwnProperty(nextPriority));

  return sortByPriority(matched, remainingPriorities)
    .sort((a, b) => (a[nextPriority] > b[nextPriority]) ? 1 : -1)
    .concat(sortByPriority(remainingData, remainingPriorities));
}

这里有一个如何使用它的例子。

const data = [
  { id: 1,                         mediumPriority: 'bbb', lowestPriority: 'ggg' },
  { id: 2, highestPriority: 'bbb', mediumPriority: 'ccc', lowestPriority: 'ggg' },
  { id: 3,                         mediumPriority: 'aaa', lowestPriority: 'ggg' },
];

const priorities = [
  'highestPriority',
  'mediumPriority',
  'lowestPriority'
];


const sorted = sortByPriority(data, priorities);

这将首先根据属性的优先级排序,然后根据属性的值进行排序。

为什么复杂化?只需要整理两次!这是完美的: (只要确保将重要性顺序从低到高颠倒过来就行了):

jj.sort( (a, b) => (a.id >= b.id) ? 1 : -1 );
jj.sort( (a, b) => (a.status >= b.status) ? 1 : -1 );

我一直在寻找类似的东西,最后得到了这个:

首先,我们有一个或多个排序函数,总是返回0、1或-1:

const sortByTitle = (a, b): number => 
  a.title === b.title ? 0 : a.title > b.title ? 1 : -1;

您可以为想要排序的其他属性创建更多函数。

然后我有一个函数将这些排序函数合并为一个:

const createSorter = (...sorters) => (a, b) =>
  sorters.reduce(
    (d, fn) => (d === 0 ? fn(a, b) : d),
    0
  );

这可以用来以一种可读的方式组合上述排序函数:

const sorter = createSorter(sortByTitle, sortByYear)

items.sort(sorter)

当一个排序函数返回0时,将调用下一个排序函数进行进一步排序。

通过添加3个相对简单的帮助程序,可以构建一个非常直观的功能解决方案。在深入研究之前,我们先来了解一下用法:

function usage(homes, { asc, desc, fallback }) { homes.sort(fallback( asc(home => home.city), desc(home => parseInt(home.price, 10)), )); console.log(homes); } var homes = [{ h_id: "3", city: "Dallas", state: "TX", zip: "75201", price: "162500", }, { h_id: "4", city: "Bevery Hills", state: "CA", zip: "90210", price: "319250", }, { h_id: "6", city: "Dallas", state: "TX", zip: "75000", price: "556699", }, { h_id: "5", city: "New York", state: "NY", zip: "00010", price: "962500", }]; const SortHelpers = (function () { const asc = (fn) => (a, b) => (a = fn(a), b = fn(b), -(a < b) || +(a > b)); const desc = (fn) => (a, b) => asc(fn)(b, a); const fallback = (...fns) => (a, b) => fns.reduce((diff, fn) => diff || fn(a, b), 0); return { asc, desc, fallback }; })(); usage(homes, SortHelpers);

如果你向下滚动代码片段,你可能已经看到了helper:

const asc  = (fn) => (a, b) => (a = fn(a), b = fn(b), -(a < b) || +(a > b));
const desc = (fn) => (a, b) => asc(fn)(b, a);
const fallback = (...fns) => (a, b) => fns.reduce((diff, fn) => diff || fn(a, b), 0);

让我快速解释一下这些函数的作用。

asc creates a comparator function. The provided function fn is called for both the comparator arguments a and b. The results of the two function calls are then compared. -1 is returned if resultA < resultB, 1 is returned if resultA > resultB, or 0 otherwise. These return values correspond with an ascending order direction. It could also be written like this: function asc(fn) { return function (a, b) { // apply `fn` to both `a` and `b` a = fn(a); b = fn(b); if (a < b) return -1; if (a > b) return 1; return 0; // or `return -(a < b) || +(a > b)` for short }; } desc is super simple, since it just calls asc but swaps the a and b arguments, resulting in descending order instead of ascending. fallback (there might be a better name for this) allows us to use multiple comparator functions with a single sort. Both asc and desc can be passed to sort by themself. homes.sort(asc(home => home.city)) There is however an issue if you want to combine multiple comparator functions. sort only accepts a single comparator function. fallback combines multiple comparator functions into a single comparator. The first comparator is called with arguments a and b, if the comparator returns the value 0 (meaning that the values are equal) then we fall back to the next comparator. This continues until a non-0 value is found, or until all comparators are called, in which case the return value is 0.

也可以为fallback()提供自定义比较器函数。假设您想使用localeCompare()而不是比较字符串与<和>。在这种情况下,您可以将asc(home => home.city)替换为(a, b) => a.city.localeCompare(b.city)。

homes.sort(fallback(
  (a, b) => a.city.localeCompare(b.city),
  desc(home => parseInt(home.price, 10)),
));

需要注意的一点是,在与<和>比较时,未定义的值总是返回false。因此,如果一个值可能缺失,您可能希望首先根据它的存在进行排序。

homes.sort(fallback(
  // homes with optionalProperty first, true (1) > false (0) so we use desc
  desc(home => home.optionalProperty != null), // checks for both null and undefined
  asc(home => home.optionalProperty),
  // ...
))

因为用localeCompare()比较字符串是一件很常见的事情,所以可以将其作为asc()的一部分。

function hasMethod(item, methodName) {
  return item != null && typeof item[methodName] === "function";
}

function asc(fn) {
  return function (a, b) {
    a = fn(a);
    b = fn(b);

    const areLocaleComparable =
      hasMethod(a, "localeCompare") && hasMethod(b, "localeCompare");

    if (areLocaleComparable) return a.localeCompare(b);

    return -(a < b) || +(a > b);
  };
}