JavaScriptの文字列プロパティ値でオブジェクトの配列をソートする



Answers

渡す値によってオブジェクトをソートする動的ソート機能を作成することもできます。

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"));

プロトタイプに追加する

(下の実装はMike Rのanswer触発されていanswer )

ネイティブオブジェクトプロトタイプを変更することはお勧めしませんが、独自のオブジェクトに実装できるように例を挙げるだけです (サポートする環境では、次のセクションに示すように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」の方法

IE v9.0以降をターゲットにしている場合は、前述のように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をそのままにします。

Question

私はJavaScriptオブジェクトの配列を持っています:

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

JavaScriptのlast_nomの値でソートするにはどうすればよいですか?

私はsort(a,b)について知っていsort(a,b)が、それは文字列と数字だけで動作するようです。 オブジェクトにtoStringメソッドを追加する必要はありますか?




// 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/ : http://www.levihackwith.com/code-snippet-how-to-sort-an-array-of-json-objects-by-property/




EgeÖzcanコードの追加のdescパラメータ

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



姓が重複している場合は、名前で名前を並べ替えることができます。

obj.sort(function(a,b){
  if(a.last_nom< b.last_nom) return -1;
  if(a.last_nom >b.last_nom) return 1;
  if(a.first_nom< b.first_nom) return -1;
  if(a.first_nom >b.first_nom) return 1;
  return 0;
});



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"));



カスタム比較関数を使用する代わりに、カスタムtoString()メソッド(デフォルトの比較関数によって呼び出される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();



私にはうまくいくコードがあります:

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

更新:常に動作していないので、正しくありません:(




Ramdaを使用して、

npm ramdaをインストールする

import R from 'ramda'
var objs = [ 
    { first_nom: 'Lazslo', last_nom: 'Jamf'     },
    { first_nom: 'Pig',    last_nom: 'Bodine'   },
    { first_nom: 'Pirate', last_nom: 'Prentice' }
];
var ascendingSortedObjs = R.sortBy(R.prop('last_nom'), objs)
var descendingSortedObjs = R.reverse(ascendingSortedObjs)



なぜ人々がそれをとても複雑にするのかを知りません。

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;
});

演算子をスワップしてアルファベット順の逆順にソートします。




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

あなたは私の強化が非常にうまく役立つと思うプロパティを介してそれを並べ替えるしたい場合。 私はこのようなオブジェクトに新しい機能を追加します:

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

そして今、あなたはこの方法で並べ替えることができます:

obj.sortBy('a.a');

JSFiddleのCommpleteスクリプトを参照してください




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");



使用例:

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){return b.last_nom>a.last_nom})



ここでは多くの良い答えがありますが、もっと複雑なソートを達成するために非常に簡単に拡張できることを指摘したいと思います。 あなたがしなければならないのは、OR演算子を使って以下のような比較関数を連鎖させることです:

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

ここで、 fn1fn2 、...は[-1,0,1]を返すソート関数です。 この結果、「fn1によるソート」、「fn2によるソート」がSQLのORDER BYとほぼ同じ結果になります。

この解決法は、 || trueに変換できる最初の評価式に評価される演算子。

最も単純なフォームは、次のように1つのインライン関数しか持たない:

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

last_nom 2つのステップがあると、 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") )

ここでのポイントは、機能的なアプローチを備えた純粋なJavaScriptが、外部ライブラリや複雑なコードがなくても、あなたを長い道のりに導くことができることです。 文字列解析も行わなければならないので、非常に効果的です




Links