arrays الدوال - فرز مصفوفة كائنات بقيمة الخاصية سلسلة في JavaScript




جافا سكريبت (25)

لدي مجموعة من كائنات JavaScript:

var objs = [ 
    { first_nom: 'Lazslo', last_nom: 'Jamf'     },
    { first_nom: 'Pig',    last_nom: 'Bodine'   },
    { first_nom: 'Pirate', last_nom: 'Prentice' }
];

كيف يمكنني فرزها حسب قيمة last_nom في JavaScript؟

أنا أعرف عن sort(a,b) ، ولكن يبدو أن ذلك يعمل فقط على الأوتار والأرقام. هل أحتاج إلى إضافة طريقة toString إلى الكائنات الخاصة بي؟


Answers

objs.sort(function(a,b){return b.last_nom>a.last_nom})

الفرز (أكثر) صفائف معقدة من الكائنات

نظرًا لأنك ربما تواجه هياكل بيانات أكثر تعقيدًا مثل هذا الصفيف ، فسوف أقوم بتوسيع الحل.

TL، DR

هي أكثر نسخة قابلة للتوصيل على أساس answer الجميلة جدا @ege-Özcan .

مشكلة

واجهت أدناه ولم أستطع تغييرها. أنا أيضا لم أكن أريد أن تقوم بتسوية الكائن مؤقتا. كما أنني لم أكن أرغب في استخدام تسطير / تسريح ، لا سيما لأسباب تتعلق بالأداء والمرح لتنفيذها بنفسي.

var People = [
   {Name: {name: "Name", surname: "Surname"}, Middlename: "JJ"},
   {Name: {name: "AAA", surname: "ZZZ"}, Middlename:"Abrams"},
   {Name: {name: "Name", surname: "AAA"}, Middlename: "Wars"}
];

هدف

الهدف هو فرزها بشكل أساسي بواسطة People.Name.name وثانياً بواسطة People.Name.surname

العقبات

الآن ، في الحل الأساسي يستخدم تدوين قوس لحساب الخصائص لفرز حيوي. هنا ، على الرغم من ذلك ، سيتعين علينا إنشاء People['Name.name'] قوس بشكل ديناميكي أيضًا ، لأنك تتوقع أن بعض People['Name.name'] مثل People['Name.name'] سيعملون - وهذا لا يحدث.

ﺑﺑﺳﺎطﺔ ﻋﻣل People['Name']['name'] ، ﻣن ﺟﮭﺔ أﺧرى ، ﺛﺎﺑت وﯾﺳﻣﺢ ﻟك ﻓﻘط ﺑﺎﻧﺧﻔﺎض اﻟﻣﺳﺗوى اﻟوطﻧﻲ.

حل

وستكون الإضافة الرئيسية هنا هي النزول إلى شجرة الكائن وتحديد قيمة الورقة الأخيرة ، وعليك أن تحدد ، وكذلك أي ورقة وسيطة.

var People = [
   {Name: {name: "Name", surname: "Surname"}, Middlename: "JJ"},
   {Name: {name: "AAA", surname: "ZZZ"}, Middlename:"Abrams"},
   {Name: {name: "Name", surname: "AAA"}, Middlename: "Wars"}
];

People.sort(dynamicMultiSort(['Name','name'], ['Name', '-surname']));
// Results in...
// [ { Name: { name: 'AAA', surname: 'ZZZ' }, Middlename: 'Abrams' },
//   { Name: { name: 'Name', surname: 'Surname' }, Middlename: 'JJ' },
//   { Name: { name: 'Name', surname: 'AAA' }, Middlename: 'Wars' } ]

// same logic as above, but strong deviation for dynamic properties 
function dynamicSort(properties) {
  var sortOrder = 1;
  // determine sort order by checking sign of last element of array
  if(properties[properties.length - 1][0] === "-") {
    sortOrder = -1;
    // Chop off sign
    properties[properties.length - 1] = properties[properties.length - 1].substr(1);
  }
  return function (a,b) {
    propertyOfA = recurseObjProp(a, properties)
    propertyOfB = recurseObjProp(b, properties)
    var result = (propertyOfA < propertyOfB) ? -1 : (propertyOfA > propertyOfB) ? 1 : 0;
    return result * sortOrder;
  };
}

/**
 * Takes an object and recurses down the tree to a target leaf and returns it value
 * @param  {Object} root - Object to be traversed.
 * @param  {Array} leafs - Array of downwards traversal. To access the value: {parent:{ child: 'value'}} -> ['parent','child']
 * @param  {Number} index - Must not be set, since it is implicit.
 * @return {String|Number}       The property, which is to be compared by sort.
 */
function recurseObjProp(root, leafs, index) {
  index ? index : index = 0
  var upper = root
  // walk down one level
  lower = upper[leafs[index]]
  // Check if last leaf has been hit by having gone one step too far.
  // If so, return result from last step.
  if (!lower) {
    return upper
  }
  // Else: recurse!
  index++
  // HINT: Bug was here, for not explicitly returning function
  // https://.com/a/17528613/3580261
  return recurseObjProp(lower, leafs, index)
}

/**
 * Multi-sort your array by a set of properties
 * @param {...Array} Arrays to access values in the form of: {parent:{ child: 'value'}} -> ['parent','child']
 * @return {Number} Number - number for sort algorithm
 */
function dynamicMultiSort() {
  var args = Array.prototype.slice.call(arguments); // slight deviation to base

  return function (a, b) {
    var i = 0, result = 0, numberOfProperties = args.length;
    // REVIEW: slightly verbose; maybe no way around because of `.sort`-'s nature
    // Consider: `.forEach()`
    while(result === 0 && i < numberOfProperties) {
      result = dynamicSort(args[i])(a, b);
      i++;
    }
    return result;
  }
}

مثال

مثال العمل على JSBin


function compare(propName) {
    return function(a,b) {
        if (a[propName] < b[propName])
            return -1;
        if (a[propName] > b[propName])
            return 1;
        return 0;
    };
}

objs.sort(compare("last_nom"));

underscore.js

استخدام تسطير ، صغيره ورائع ...

sortBy_.sortBy (list، iterator، [context]) لعرض نسخة مرتبة من القائمة مرتبة في ترتيب تصاعدي حسب نتائج تشغيل كل قيمة من خلال المكرّر. قد يكون Iterator أيضًا اسم سلسلة الخاصية للفرز حسب (على سبيل المثال ، الطول).

var objs = [ 
  { first_nom: 'Lazslo',last_nom: 'Jamf' },
  { first_nom: 'Pig', last_nom: 'Bodine'  },
  { first_nom: 'Pirate', last_nom: 'Prentice' }
];

var sortedObjs = _.sortBy( objs, 'first_nom' );

مثال للاستخدام:

objs.sort(sortBy('last_nom'));

النصي:

/**
 * @description 
 * Returns a function which will sort an
 * array of objects by the given key.
 * 
 * @param  {String}  key
 * @param  {Boolean} reverse
 * @return {Function}     
 */
function sortBy(key, reverse) {

  // Move smaller items towards the front
  // or back of the array depending on if
  // we want to sort the array in reverse
  // order or not.
  var moveSmaller = reverse ? 1 : -1;

  // Move larger items towards the front
  // or back of the array depending on if
  // we want to sort the array in reverse
  // order or not.
  var moveLarger = reverse ? -1 : 1;

  /**
   * @param  {*} a
   * @param  {*} b
   * @return {Number}
   */
  return function(a, b) {
    if (a[key] < b[key]) {
      return moveSmaller;
    }
    if (a[key] > b[key]) {
      return moveLarger;
    }
    return 0;
  };

}

قد تحتاج إلى تحويلها إلى الحالة الصغيرة لمنعها من الارتباك.

objs.sort(function (a,b) {

var nameA=a.last_nom.toLowerCase(), nameB=b.last_nom.toLowerCase()

if (nameA < nameB)
  return -1;
if (nameA > nameB)
  return 1;
return 0;  //no sorting

})

So here is one sorting algorithm which can sort in any order , throughout array of any kind of objects , without the restriction of datatype comparison ( ie Number , String )

function smoothSort(items,prop,reverse) {  
    var length = items.length;
    for (var i = (length - 1); i >= 0; i--) {
        //Number of passes
        for (var j = (length - i); j > 0; j--) {
            //Compare the adjacent positions
            if(reverse){
              if (items[j][prop] > items[j - 1][prop]) {
                //Swap the numbers
                var tmp = items[j];
                items[j] = items[j - 1];
                items[j - 1] = tmp;
            }
            }

            if(!reverse){
              if (items[j][prop] < items[j - 1][prop]) {
                  //Swap the numbers
                  var tmp = items[j];
                  items[j] = items[j - 1];
                  items[j - 1] = tmp;
              }
            }
        }
    }

    return items;
}
  • the first argument items is the array of objects ,

  • prop is the key of the object on which you want to sort ,

  • reverse is a boolean parameter which on being true results in Ascending order and in false it returns descending order.


الجمع بين حل Ege الحيوي مع فكرة Vinay ، يمكنك الحصول على حل قوي وجيد:

Array.prototype.sortBy = function() {
    function _sortByAttr(attr) {
        var sortOrder = 1;
        if (attr[0] == "-") {
            sortOrder = -1;
            attr = attr.substr(1);
        }
        return function(a, b) {
            var result = (a[attr] < b[attr]) ? -1 : (a[attr] > b[attr]) ? 1 : 0;
            return result * sortOrder;
        }
    }
    function _getSortFunc() {
        if (arguments.length == 0) {
            throw "Zero length arguments not allowed for Array.sortBy()";
        }
        var args = arguments;
        return function(a, b) {
            for (var result = 0, i = 0; result == 0 && i < args.length; i++) {
                result = _sortByAttr(args[i])(a, b);
            }
            return result;
        }
    }
    return this.sort(_getSortFunc.apply(null, arguments));
}

الاستعمال:

// Utility for printing objects
Array.prototype.print = function(title) {
    console.log("************************************************************************");
    console.log("**** "+title);
    console.log("************************************************************************");
    for (var i = 0; i < this.length; i++) {
        console.log("Name: "+this[i].FirstName, this[i].LastName, "Age: "+this[i].Age);
    }
}

// Setup sample data
var arrObj = [
    {FirstName: "Zach", LastName: "Emergency", Age: 35},
    {FirstName: "Nancy", LastName: "Nurse", Age: 27},
    {FirstName: "Ethel", LastName: "Emergency", Age: 42},
    {FirstName: "Nina", LastName: "Nurse", Age: 48},
    {FirstName: "Anthony", LastName: "Emergency", Age: 44},
    {FirstName: "Nina", LastName: "Nurse", Age: 32},
    {FirstName: "Ed", LastName: "Emergency", Age: 28},
    {FirstName: "Peter", LastName: "Physician", Age: 58},
    {FirstName: "Al", LastName: "Emergency", Age: 51},
    {FirstName: "Ruth", LastName: "Registration", Age: 62},
    {FirstName: "Ed", LastName: "Emergency", Age: 38},
    {FirstName: "Tammy", LastName: "Triage", Age: 29},
    {FirstName: "Alan", LastName: "Emergency", Age: 60},
    {FirstName: "Nina", LastName: "Nurse", Age: 54}
];

//Unit Tests
arrObj.sortBy("LastName").print("LastName Ascending");
arrObj.sortBy("-LastName").print("LastName Descending");
arrObj.sortBy("LastName", "FirstName", "-Age").print("LastName Ascending, FirstName Ascending, Age Descending");
arrObj.sortBy("-FirstName", "Age").print("FirstName Descending, Age Ascending");
arrObj.sortBy("-Age").print("Age Descending");

// Sort Array of Objects

// Data
var booksArray = [
    { first_nom: 'Lazslo', last_nom: 'Jamf'     },
    { first_nom: 'Pig',    last_nom: 'Bodine'   },
    { first_nom: 'Pirate', last_nom: 'Prentice' }
];

// Property to Sort By
var args = "last_nom";

// Function to Sort the Data by given Property
function sortByProperty(property) {
    return function (a, b) {
        var sortStatus = 0,
            aProp = a[property].toLowerCase(),
            bProp = b[property].toLowerCase();
        if (aProp < bProp) {
            sortStatus = -1;
        } else if (aProp > bProp) {
            sortStatus = 1;
        }
        return sortStatus;
    };
}

// Implementation
var sortedArray = booksArray.sort(sortByProperty(args));

console.log("sortedArray: " + JSON.stringify(sortedArray) );

Console log output:

"sortedArray: 
[{"first_nom":"Pig","last_nom":"Bodine"},
{"first_nom":"Lazslo","last_nom":"Jamf"},
{"first_nom":"Pirate","last_nom":"Prentice"}]"

مقتبس على أساس هذا المصدر: http://www.levihackwith.com/code-snippet-how-to-sort-an-array-of-json-objects-by-property/


لا تجعل الناس يجعلون الأمر معقدًا للغاية:

objs.sort(function(a, b){
  return a.last_nom > b.last_nom;
});

لمحركات أكثر صرامة:

objs.sort(function(a, b){
  return a.last_nom == b.last_nom ? 0 : +(a.last_nom > b.last_nom) || -1;
});

قم بتبديل المشغل لجعله مرتبة حسب الترتيب الأبجدي العكسي.


أنا فقط حسّنت نوع Ege Özcan الديناميكي للغوص العميق داخل الأجسام. إذا كانت البيانات تبدو كالتالي:

obj = [
    {
        a: { a: 1, b: 2, c: 3 },
        b: { a: 4, b: 5, c: 6 }
    },
    { 
        a: { a: 3, b: 2, c: 1 },
        b: { a: 6, b: 5, c: 4 }
}];

وإذا كنت تريد فرزها على خاصية aa أعتقد أن تحسيني يساعد بشكل جيد. أقوم بإضافة وظائف جديدة إلى كائنات مثل:

Object.defineProperty(Object.prototype, 'deepVal', {
    enumerable: false,
    writable: true,
    value: function (propertyChain) {
        var levels = propertyChain.split('.');
        parent = this;
        for (var i = 0; i < levels.length; i++) {
            if (!parent[levels[i]])
                return undefined;
            parent = parent[levels[i]];
        }
        return parent;
    }
});

وغيرت وظيفة الإرجاع _dynamicSort :

return function (a,b) {
        var result = ((a.deepVal(property) > b.deepVal(property)) - (a.deepVal(property) < b.deepVal(property)));
        return result * sortOrder;
    }

والآن يمكنك الفرز بواسطة aa بهذه الطريقة:

obj.sortBy('a.a');

انظر البرنامج النصي JSFiddle في JSFiddle


لدي جزء من الشفرة يعمل لي:

arr.sort((a, b) => a.name > b.name)

استكمال: لا يعمل دائما ، لذلك ليس صحيحا :(


يمكنك أيضًا إنشاء دالة فرز ديناميكية تقوم بفرز الكائنات حسب قيمتها التي تقوم بتمريرها:

function dynamicSort(property) {
    var sortOrder = 1;
    if(property[0] === "-") {
        sortOrder = -1;
        property = property.substr(1);
    }
    return function (a,b) {
        var result = (a[property] < b[property]) ? -1 : (a[property] > b[property]) ? 1 : 0;
        return result * sortOrder;
    }
}

لذلك يمكنك الحصول على مجموعة من الكائنات مثل هذا:

var People = [
    {Name: "Name", Surname: "Surname"},
    {Name:"AAA", Surname:"ZZZ"},
    {Name: "Name", Surname: "AAA"}
];

... وستعمل عندما تفعل:

People.sort(dynamicSort("Name"));
People.sort(dynamicSort("Surname"));
People.sort(dynamicSort("-Surname"));

في الواقع هذا بالفعل يجيب على السؤال. الجزء أدناه مكتوب لأن العديد من الناس اتصلوا بي ، وشكوا أنه لا يعمل مع معايير متعددة .

معلمات متعددة

يمكنك استخدام الوظيفة أدناه لتوليد وظائف الفرز بمعلمات فرز متعددة.

function dynamicSortMultiple() {
    /*
     * save the arguments object as it will be overwritten
     * note that arguments object is an array-like object
     * consisting of the names of the properties to sort by
     */
    var props = arguments;
    return function (obj1, obj2) {
        var i = 0, result = 0, numberOfProperties = props.length;
        /* try getting a different result from 0 (equal)
         * as long as we have extra properties to compare
         */
        while(result === 0 && i < numberOfProperties) {
            result = dynamicSort(props[i])(obj1, obj2);
            i++;
        }
        return result;
    }
}

مما يمكّنك من القيام بشيء كالتالي:

People.sort(dynamicSortMultiple("Name", "-Surname"));

مضيفا على النموذج

(تم استلهام التطبيق الموجود أدناه من answer مايك R )

لا أوصي بتغيير نموذج أصلي للكائن الأصلي ولكن فقط لإعطاء مثال حتى تتمكن من تنفيذه على الكائنات الخاصة بك (بالنسبة للبيئات التي تدعمه ، يمكنك أيضًا استخدام Object.defineProperty كما هو موضح في القسم التالي ، على الأقل لا يكون لها تأثير جانبي سلبي للعدود ، كما هو موضح في الجزء الأخير)

سيكون تنفيذ النموذج الأولي شيئًا مثل ما يلي ( إليك مثال عملي ):

//Don't just copy-paste this code. You will break the "for-in" loops
!function() {
    function _dynamicSortMultiple(attr) {
       /* dynamicSortMultiple function body comes here */
    }
    function _dynamicSort(property) {
        /* dynamicSort function body comes here */
    }
    Array.prototype.sortBy = function() {
        return this.sort(_dynamicSortMultiple.apply(null, arguments));
    }
}();

طريقة "OK" لإضافته إلى النموذج الأولي

إذا كنت تستهدف Object.defineProperty ، كما ذكرت سابقًا ، فاستخدم Object.defineProperty مثل هذا ( مثال عملي ):

//Won't work below IE9, but totally safe otherwise
!function() {
    function _dynamicSortMultiple(attr) {
       /* dynamicSortMultiple function body comes here */
    }
    function _dynamicSort(property) {
        /* dynamicSort function body comes here */
    }
    Object.defineProperty(Array.prototype, "sortBy", {
        enumerable: false,
        writable: true,
        value: function() {
            return this.sort(_dynamicSortMultiple.apply(null, arguments));
        }
    });
}();

يمكن أن يكون هذا حلًا مقبولًا حتى يصل عامل الربط .

كل هذه المتعة النموذجية تمكن هذا:

People.sortBy("Name", "-Surname");

يجب عليك قراءة هذا

إذا كنت تستخدم أسلوب الوصول إلى النموذج المباشر (Object.defineProperty على ما يرام) و رمز آخر لا تحقق hasOwnProperty ، تموت القطط! حسنًا ، لنكون صادقين ، لا ضرر لأي هريرة فعلًا ولكن ربما ستنكسر الأشياء وسيكرهك كل مطور آخر في فريقك:

نرى أن الماضي "SortBy"؟ بلى. ليس بارد استخدم Object.defineProperty حيث يمكنك ، واترك Array.prototype بمفرده.


أعلم أن هذا السؤال قديم جدًا ، لكنني لم أشاهد أي تنفيذ مماثل لي.
يستند هذا الإصدار على لغة شوارتسيان التحويل .

function sortByAttribute(array, ...attrs) {
  // generate an array of predicate-objects contains
  // property getter, and descending indicator
  let predicates = attrs.map(pred => {
    let descending = pred.charAt(0) === '-' ? -1 : 1;
    pred = pred.replace(/^-/, '');
    return {
      getter: o => o[pred],
      descend: descending
    };
  });
  // schwartzian transform idiom implementation. aka: "decorate-sort-undecorate"
  return array.map(item => {
    return {
      src: item,
      compareValues: predicates.map(predicate => predicate.getter(item))
    };
  })
  .sort((o1, o2) => {
    let i = -1, result = 0;
    while (++i < predicates.length) {
      if (o1.compareValues[i] < o2.compareValues[i]) result = -1;
      if (o1.compareValues[i] > o2.compareValues[i]) result = 1;
      if (result *= predicates[i].descend) break;
    }
    return result;
  })
  .map(item => item.src);
}

في ما يلي مثال على كيفية استخدامه:

let games = [
  { name: 'Pako',              rating: 4.21 },
  { name: 'Hill Climb Racing', rating: 3.88 },
  { name: 'Angry Birds Space', rating: 3.88 },
  { name: 'Badland',           rating: 4.33 }
];

// sort by one attribute
console.log(sortByAttribute(games, 'name'));
// sort by mupltiple attributes
console.log(sortByAttribute(games, '-rating', 'name'));

معلمات desc إضافية لرمز Ege Özcan

function dynamicSort(property, desc) {
    if (desc) {
        return function (a, b) {
            return (a[property] > b[property]) ? -1 : (a[property] < b[property]) ? 1 : 0;
        }   
    }
    return function (a, b) {
        return (a[property] < b[property]) ? -1 : (a[property] > b[property]) ? 1 : 0;
    }
}

هناك العديد من الإجابات الجيدة هنا ، لكني أود أن أشير إلى أنه يمكن تمديدها ببساطة شديدة لتحقيق فرز أكثر تعقيدًا. الشيء الوحيد الذي عليك القيام به هو استخدام عامل التشغيل OR لسلسلة المقارنات الوظيفية مثل:

objs.sort((a,b)=> fn1(a,b) || fn2(a,b) || fn3(a,b) )

حيث fn1 ، fn2 ، ... هي وظائف الفرز التي ترجع [-1،0،1]. هذه النتائج في "الفرز بواسطة fn1" ، "الفرز حسب fn2" وهو يساوي إلى حد كبير ORDER BY في SQL.

يعتمد هذا الحل على سلوك || المشغل الذي يتم تقييمه لأول تعبير تم تقييمه والذي يمكن تحويله إلى true .

أبسط شكل له وظيفة مدمجة واحدة فقط مثل:

// ORDER BY last_nom
objs.sort((a,b)=> a.last_nom.localeCompare(b.last_nom) )

بعد خطوتين مع last_nom ، first_nom ترتيب الفرز first_nom كما يلي:

// ORDER_BY last_nom, first_nom
objs.sort((a,b)=> a.last_nom.localeCompare(b.last_nom) || 
                  a.first_nom.localeCompare(b.first_nom)  )

يمكن أن تكون وظيفة المقارنة العامة شيئًا كالتالي:

// ORDER BY <n>
let cmp = (a,b,n)=>a[n].localeCompare(b[n])

يمكن توسيع هذه الوظيفة لدعم الحقول الرقمية ، وحساسية الحالة ، وأنواع البيانات التحكيمية إلخ.

يمكنك استخدامها مع ربطهم حسب أولوية الترتيب:

// ORDER_BY last_nom, first_nom
objs.sort((a,b)=> cmp(a,b, "last_nom") || cmp(a,b, "first_nom") )
// ORDER_BY last_nom, first_nom DESC
objs.sort((a,b)=> cmp(a,b, "last_nom") || -cmp(a,b, "first_nom") )
// ORDER_BY last_nom DESC, first_nom DESC
objs.sort((a,b)=> -cmp(a,b, "last_nom") || -cmp(a,b, "first_nom") )

النقطة هنا هي أن جافا سكريبت النقي مع النهج الوظيفي يمكن أن يأخذك شوطا طويلا دون مكتبات خارجية أو رمز معقد. وهو أيضًا فعال للغاية ، حيث لا يجب إجراء تحليل للأوتار


Given the original example:

var objs = [ 
    { first_nom: 'Lazslo', last_nom: 'Jamf'     },
    { first_nom: 'Pig',    last_nom: 'Bodine'   },
    { first_nom: 'Pirate', last_nom: 'Prentice' }
];

Sort by multiple fields:

objs.sort(function(left, right) {
    var last_nom_order = left.last_nom.localeCompare(right.last_nom);
    var first_nom_order = left.first_nom.localeCompare(right.first_nom);
    return last_nom_order || first_nom_order;
});

ملاحظات

  • a.localeCompare(b) is universally supported and returns -1,0,1 if a<b , a==b , a>b respectively.
  • || in the last line gives last_nom priority over first_nom .
  • Subtraction works on numeric fields: var age_order = left.age - right.age;
  • Negate to reverse order, return -last_nom_order || -first_nom_order || -age_order;

حل بسيط وسريع لهذه المشكلة باستخدام الوراثة الأولية:

Array.prototype.sortBy = function(p) {
  return this.slice(0).sort(function(a,b) {
    return (a[p] > b[p]) ? 1 : (a[p] < b[p]) ? -1 : 0;
  });
}

مثال / الاستخدام

objs = [{age:44,name:'vinay'},{age:24,name:'deepak'},{age:74,name:'suresh'}];

objs.sortBy('age');
// Returns
// [{"age":24,"name":"deepak"},{"age":44,"name":"vinay"},{"age":74,"name":"suresh"}]

objs.sortBy('name');
// Returns
// [{"age":24,"name":"deepak"},{"age":74,"name":"suresh"},{"age":44,"name":"vinay"}]

تحديث: لم يعد يعدل الصفيف الأصلي.


هذه مشكلة بسيطة ، لا أعرف لماذا يمتلك الناس مثل هذا الحل المعقد.
وظيفة فرز بسيطة (تعتمد على خوارزمية الفرز السريع ):

function sortObjectsArray(objectsArray, sortKey)
        {
            // Quick Sort:
            var retVal;

            if (1 < objectsArray.length)
            {
                var pivotIndex = Math.floor((objectsArray.length - 1) / 2);  // middle index
                var pivotItem = objectsArray[pivotIndex];                    // value in the middle index
                var less = [], more = [];

                objectsArray.splice(pivotIndex, 1);                          // remove the item in the pivot position
                objectsArray.forEach(function(value, index, array)
                {
                    value[sortKey] <= pivotItem[sortKey] ?                   // compare the 'sortKey' proiperty
                        less.push(value) :
                        more.push(value) ;
                });

                retVal = sortObjectsArray(less, sortKey).concat([pivotItem], sortObjectsArray(more, sortKey));
            }
            else
            {
                retVal = objectsArray;
            }

            return retVal;
        }

استخدم المثال:

var myArr = 
        [
            { val: 'x', idx: 3 },
            { val: 'y', idx: 2 },
            { val: 'z', idx: 5 },
        ];
myArr = sortObjectsArray(myArr, 'idx');

بدلاً من استخدام دالة مقارنة مخصصة ، يمكنك أيضًا إنشاء نوع كائن مع طريقة toString() مخصصة (يتم استدعاؤها بواسطة وظيفة المقارنة الافتراضية):

function Person(firstName, lastName) {
    this.firtName = firstName;
    this.lastName = lastName;
}

Person.prototype.toString = function() {
    return this.lastName + ', ' + this.firstName;
}

var persons = [ new Person('Lazslo', 'Jamf'), ...]
persons.sort();

في ES6 / ES2015 أو ما يليه ، يمكنك إجراء ذلك على النحو التالي:

objs.sort((a, b) => a.last_nom.localeCompare(b.last_nom));

خيار واحد آخر:

var someArray = [...];

function generateSortFn(prop, reverse) {
    return function (a, b) {
        if (a[prop] < b[prop]) return reverse ? 1 : -1;
        if (a[prop] > b[prop]) return reverse ? -1 : 1;
        return 0;
    };
}

someArray.sort(generateSortFn('name', true));

فرز تصاعدي بشكل افتراضي.


باستخدام المثال الخاص بك ، تحتاج إلى الفرز حسب حقلين (الاسم الأخير والاسم الأول) ، بدلاً من واحد. يمكنك استخدام مكتبة Alasql لجعل هذا الترتيب في سطر واحد:

var res = alasql('SELECT * FROM ? ORDER BY last_nom, first_nom',[objs]);

جرب هذا المثال في jsFiddle .


Lodash.js (superset of Underscore.js )

من الجيد عدم إضافة إطار عمل لكل جزء بسيط من المنطق ، ولكن الاعتماد على أطر المنفعة التي تم اختبارها بشكل جيد ، وتسريع التنمية وتقليل كمية الحشرات المكتوبة ليس من العار.

Lodash تنتج رمز نظيفة جدا وتروج نمط برمجة أكثر وظيفية ، مما يؤدي إلى أقل الأخطاء. في لمحة واحدة يصبح واضحا ما القصد إذا كان الرمز.

يمكن حل مشكلة OP ببساطة على النحو التالي:

const sortedObjs = _.sortBy(objs, 'last_nom');

مزيد من المعلومات؟ على سبيل المثال ، نحن نتبع كائنًا متداخلاً:

const users = [
  { 'user': {'name':'fred', 'age': 48}},
  { 'user': {'name':'barney', 'age': 36 }},
  { 'user': {'name':'wilma'}},
  { 'user': {'name':'betty', 'age': 32}}
];

يمكننا الآن استخدام _.property الاختصار user.age لتحديد المسار إلى الخاصية التي يجب مطابقتها. سنقوم بتصنيف كائنات المستخدم بواسطة خاصية العمر المتداخل. نعم ، إنه يسمح بتطابق خاصية متداخلة!

const sortedObjs = _.sortBy(users, ['user.age']);

هل تريد عكس ذلك؟ ليس هناك أى مشكلة. استخدم _.reverse .

const sortedObjs = _.reverse(_.sortBy(users, ['user.age']));

هل تريد الجمع بين استخدام Chaining بدلاً من ذلك؟

const sortedObjs = _.chain(users).sortBy('user.age').reverse().value();

إذا كنت تستخدم JavaScript 1.6 أو أحدث (Firefox 1.5 أو أحدث) ، يمكنك استخدام Array.indexOf . بخلاف ذلك ، أعتقد أنك ستنتهي بشيء مماثل لرمزك الأصلي.





javascript arrays sorting properties