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

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

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"}
    ];

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

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


当前回答

下面的函数将允许您对一个或多个属性上的对象数组进行排序,对每个属性进行升序(默认值)或降序排序,并允许您选择是否执行区分大小写的比较。默认情况下,该函数执行不区分大小写的排序。

第一个参数必须是包含对象的数组。 后面的参数必须是一个以逗号分隔的字符串列表,这些字符串引用要排序的不同对象属性。最后一个参数(可选)是一个布尔值,用于选择是否执行区分大小写的排序——区分大小写的排序使用true。

默认情况下,该函数将按升序对每个属性/键排序。如果你想要一个特定的键按降序排序,那么取而代之的是传递一个这样格式的数组:['property_name', true]。

下面是该函数的一些示例用法,后面附有解释(其中homes是一个包含对象的数组):

objSort(homes, 'city')—>按城市排序(升序,不区分大小写)

objSort(homes, ['city', true])——>按城市排序(降序,不区分大小写)

objSort(homes, 'city', true)—>按城市然后价格排序(升序,区分大小写)

objSort(homes, 'city', 'price')——>先按城市再按价格排序(均为升序,不区分大小写)

objSort(homes, 'city', ['price', true])——>排序城市(升序)然后价格(降序),不区分大小写)

话不多说,下面是函数:

function objSort() {
    var args = arguments,
        array = args[0],
        case_sensitive, keys_length, key, desc, a, b, i;

    if (typeof arguments[arguments.length - 1] === 'boolean') {
        case_sensitive = arguments[arguments.length - 1];
        keys_length = arguments.length - 1;
    } else {
        case_sensitive = false;
        keys_length = arguments.length;
    }

    return array.sort(function (obj1, obj2) {
        for (i = 1; i < keys_length; i++) {
            key = args[i];
            if (typeof key !== 'string') {
                desc = key[1];
                key = key[0];
                a = obj1[args[i][0]];
                b = obj2[args[i][0]];
            } else {
                desc = false;
                a = obj1[args[i]];
                b = obj2[args[i]];
            }

            if (case_sensitive === false && typeof a === 'string') {
                a = a.toLowerCase();
                b = b.toLowerCase();
            }

            if (! desc) {
                if (a < b) return -1;
                if (a > b) return 1;
            } else {
                if (a > b) return -1;
                if (a < b) return 1;
            }
        }
        return 0;
    });
} //end of objSort() function

下面是一些样本数据:

var homes = [{
    "h_id": "3",
    "city": "Dallas",
    "state": "TX",
    "zip": "75201",
    "price": 162500
}, {
    "h_id": "4",
    "city": "Bevery Hills",
    "state": "CA",
    "zip": "90210",
    "price": 1000000
}, {
    "h_id": "5",
    "city": "new york",
    "state": "NY",
    "zip": "00010",
    "price": 1000000
}, {
    "h_id": "6",
    "city": "Dallas",
    "state": "TX",
    "zip": "85000",
    "price": 300000
}, {
    "h_id": "7",
    "city": "New York",
    "state": "NY",
    "zip": "00020",
    "price": 345000
}];

其他回答

这是一个通用的多维排序,允许在每个层次上进行反转和/或映射。

用Typescript编写。对于Javascript,请查看这个JSFiddle

的代码

type itemMap = (n: any) => any;

interface SortConfig<T> {
  key: keyof T;
  reverse?: boolean;
  map?: itemMap;
}

export function byObjectValues<T extends object>(keys: ((keyof T) | SortConfig<T>)[]): (a: T, b: T) => 0 | 1 | -1 {
  return function(a: T, b: T) {
    const firstKey: keyof T | SortConfig<T> = keys[0];
    const isSimple = typeof firstKey === 'string';
    const key: keyof T = isSimple ? (firstKey as keyof T) : (firstKey as SortConfig<T>).key;
    const reverse: boolean = isSimple ? false : !!(firstKey as SortConfig<T>).reverse;
    const map: itemMap | null = isSimple ? null : (firstKey as SortConfig<T>).map || null;

    const valA = map ? map(a[key]) : a[key];
    const valB = map ? map(b[key]) : b[key];
    if (valA === valB) {
      if (keys.length === 1) {
        return 0;
      }
      return byObjectValues<T>(keys.slice(1))(a, b);
    }
    if (reverse) {
      return valA > valB ? -1 : 1;
    }
    return valA > valB ? 1 : -1;
  };
}

用法示例

先按姓排序,再按名排序:

interface Person {
  firstName: string;
  lastName: string;
}

people.sort(byObjectValues<Person>(['lastName','firstName']));

按语言代码的名称排序,而不是按语言代码排序(见地图),然后按降序排序(见反向)。

interface Language {
  code: string;
  version: number;
}

// languageCodeToName(code) is defined elsewhere in code

languageCodes.sort(byObjectValues<Language>([
  {
    key: 'code',
    map(code:string) => languageCodeToName(code),
  },
  {
    key: 'version',
    reverse: true,
  }
]));

这是一个完全的欺骗,但我认为它为这个问题增加了价值,因为它基本上是一个罐装的库函数,你可以开箱即用。

如果你的代码可以访问lodash或者一个与lodash兼容的库,比如下划线,那么你可以使用_。sortBy方法。下面的代码片段直接复制自lodash文档。

示例中的注释结果看起来像是返回数组的数组,但这只是显示了顺序,而不是实际的结果,它是一个对象数组。

var users = [
  { 'user': 'fred',   'age': 48 },
  { 'user': 'barney', 'age': 36 },
  { 'user': 'fred',   'age': 40 },
  { 'user': 'barney', 'age': 34 }
];

_.sortBy(users, [function(o) { return o.user; }]);
 // => objects for [['barney', 36], ['barney', 34], ['fred', 48], ['fred', 40]]

_.sortBy(users, ['user', 'age']);
// => objects for [['barney', 34], ['barney', 36], ['fred', 40], ['fred', 48]]

按多个字段排序对象数组的最简单方法:

 let 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"}
  ];

homes.sort((a, b) => (a.city > b.city) ? 1 : -1);

输出: “Bevery山” “达拉斯” “达拉斯” “达拉斯” “纽约”

您可以使用链式排序方法,取值的增量,直到它达到不等于零的值。

var data = [{ 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" }]; data.sort(function (a, b) { return a.city.localeCompare(b.city) || b.price - a.price; }); console.log(data); .as-console-wrapper { max-height: 100% !important; top: 0; }

或者,使用es6,简单地:

data.sort((a, b) => a.city.localeCompare(b.city) || b.price - a.price);

简单的一个:

var someArray = [...];

function generateSortFn(props) {
    return function (a, b) {
        for (var i = 0; i < props.length; i++) {
            var prop = props[i];
            var name = prop.name;
            var reverse = prop.reverse;
            if (a[name] < b[name])
                return reverse ? 1 : -1;
            if (a[name] > b[name])
                return reverse ? -1 : 1;
        }
        return 0;
    };
};

someArray.sort(generateSortFn([{name: 'prop1', reverse: true}, {name: 'prop2'}]));