Подтвердить что ты не робот

Любой способ расширить метод javascript array.sort() для принятия другого параметра?

Я пытаюсь сортировать массив объектов. Я бы предпочел не писать собственный метод сортировки для каждого атрибута.

В любом случае я могу расширить встроенный метод array.sort(), чтобы принять дополнительный параметр, описывающий атрибут для сортировки? Например.

array.sort(function(a, b, attr) { return a.attr - b.attr; }, 'name');
4b9b3361

Ответ 1

Напишите генератор функций, который принимает имя свойства:

function propComparator(prop) {
    return function(a, b) {
        return a[prop] - b[prop];
    }
}

arr.sort(propComparator('name'));

Вы также можете сохранить сортировщики для последующего использования, напрямую или как параметры:

var compareNames = propComparator('name');
var compareFoos = propComparator('foo');
...
arr.sort(compareNames);
takesComparator(compareFoos);

Обновлен для ES6 и делает его так, что он действительно работает с разными типами.

Обратите внимание, что sort сортирует на месте, что может быть или не быть желательным.

const arr = [
  { name: 'John', age: 92 },
  { name: 'Dave', age: 42 },
  { name: 'Justin', age: 3 }
]

const propComparator = (propName) =>
  (a, b) => a[propName] == b[propName] ? 0 : a[propName] < b[propName] ? -1 : 1

arr.sort(propComparator('name'))
console.log("By name", arr)

arr.sort(propComparator('age'))
console.log("By age", arr)

Ответ 2

Это то, что вы ищете?

function sortByProperty(array, propertyName) {
    return array.sort(function (a, b) {
        return a[propertyName] - b[propertyName];
    });
}

var sortedByName = sortByProperty(myArray, "name");

Ответ 3

Использовать прототипы для правильного сравнения строк и чисел.

Array.prototype.sortAttr = function(attr,reverse) {
  var sorter = function(a,b) {
    var aa = a[attr];
    var bb = b[attr];
    if(aa+0==aa && bb+0==bb) return aa-bb; // numbers
    else return aa.localeCompare(bb); // strings
  }
  this.sort(function(a,b) {
    var result = sorter(a,b);
    if(reverse) result*= -1;
    return result;
  });
};

Пример

var data = [
  {name: "Josh", age: 18},
  {name: "John", age: 17},
  {name: "Bob", age: 20},
  {name: 0, age: "error"}
];

data.sortAttr("name");
// data is now sorted by name

Ответ 4

В любом случае я могу расширить встроенный метод array.sort(), чтобы принять дополнительный параметр

все вышеприведенные ответы хороши. но я подумал о добавлении некоторой информации о частичных функциях

для получения дополнительной информации см. bind в MDN и частичная функция или John Resig - частичная функция

Пример из MDN:

function list() {
  return Array.prototype.slice.call(arguments);
}

var list1 = list(1, 2, 3); // [1, 2, 3]

//  Create a function with a preset leading argument
var leadingThirtysevenList = list.bind(undefined, 37);

var list2 = leadingThirtysevenList(); // [37]
var list3 = leadingThirtysevenList(1, 2, 3); // [37, 1, 2, 3]

вот пример из Google Closure

goog.partial = function(fn, var_args) {
  var args = Array.prototype.slice.call(arguments, 1);
  return function() {
    // Prepend the bound arguments to the current arguments.
    var newArgs = Array.prototype.slice.call(arguments);
    newArgs.unshift.apply(newArgs, args);
    return fn.apply(this, newArgs);
  };
};

Использовать эту функцию

    var fn=goog.partial(numberCompare,sortField,sortDirection);
    myarray.sort (fn);


    var numberCompare = function (sortField,sortDirection,value1,value2){
      // sort code goes here
    }

Ответ 5

Фактически расширение его

Чтобы действительно расширить Array.prototype.sort, у нас есть несколько вариантов:

  • Мутировать свою подпись
  • Сортировка по множественности с помощью Decorators | Адаптеры (Parent Pattern: Wrapper)

Я был в вашей же лодке и решил использовать второй подход:

private sortAddresses = (a, b) => {
    let iPrimeFlag = this.sortAddressesByPrimaryFlag(a, b);
    let iAlphaNum = this.sortAddressesByAlphaNum(a, b);

    if (iPrimeFlag === 1) return 1;
    else return iAlphaNum;
};

private sortAddressesByPrimaryFlag(a, b) {
    if (b.primaryFlag > a.primaryFlag) return 1;
    if (b.primaryFlag < a.primaryFlag) return -1;
    return 0;
}

private sortAddressesByAlphaNum(a, b) {
    let aAddress = this.$.formatAddress(a);
    let bAddress = this.$.formatAddress(b);

    if (aAddress > bAddress) return 1;
    if (aAddress < bAddress) return -1;

    return 0;
}

Намерение

Я уже звоню this.addresses.sort(this.sortAddresses) в нескольких местах, и я хочу сохранить свой недостаток ChangeCost - особенно, зная, что мы можем получить требования для сортировки по еще большей эвристике.

Итак, чтобы следовать "Банде четырех" правил большого пальца -

Программа для интерфейса, а не для реализации.

и

Инкапсулируйте, что меняется.

- Я решил сохранить свою подпись так же, как и мой оригинальный метод.

Было бы полезно, если бы нам не пришлось проходить и менять каждую строку, где мы вызываем this.addresses.sort. Вместо этого мы хотели бы добавить неопределенное количество сортировки "эвристики" к действию сортировки.

Целью является определение приоритетов адресных объектов, primaryFlag которых 'Y', а затем строка адреса - '0000 Some St, #0000, City, ST 00000' - и сортировка этих буквенно-цифровых символов. Так как 'Y' > 'N', мы хотели бы переместить его в списке, визуально, понизив его индекс. Сортировка адресной строки alphanumerically говорит, что если 'Colorado' есть > 'Alabama', тогда мы должны нажимать 'Colorado' вниз в списке визуально, увеличивая его индекс.

Использование

Используется для сортировки Адреса разными значениями. Одно значение, primaryFlag, означает, что его [единственный] адрес по умолчанию; в моем случае primaryFlag - это жало 'Y' или 'N', а не логическое (спросите моих партнеров по команде, почему в мире?). Другое значение this.$.formatAddress(a|b) принимает этот адрес [object Object] - a и b - и вызывает formatAddress off моей песочницы this.$.

Строка if (iPrimeFlag === 1) return 1; гласит: "в любое время primaryFlag равно 1, просто ударяйте это по направлению к голове (началу) массива, в противном случае выполняйте то, что решает буквенно-цифровая эвристика", что позволяет нам устанавливать приоритеты по одной эвристике при падении назад на другой.

Также обратите внимание: .bind(undefined, 'prop') не используется в моем фактическом коде, поскольку мне это не нужно; это только для демонстрационных целей.

Теперь я знаю, что я тот человек, который предоставил некоторый TypeScript - lemme знаю, если вы не понимаете, что происходит в этом коде:)

Ура!