オブジェクトの配列を単一のキーで日付値でソートします


257

いくつかのキーと値のペアを持つオブジェクトの配列があり、「updated_at」に基づいてそれらをソートする必要があります。

[
    {
        "updated_at" : "2012-01-01T06:25:24Z",
        "foo" : "bar"
    },
    {
        "updated_at" : "2012-01-09T11:25:13Z",
        "foo" : "bar"
    },
    {
        "updated_at" : "2012-01-05T04:13:24Z",
        "foo" : "bar"
    }
]

そうするための最も効率的な方法は何ですか?


@Topenerこのリンクは、PHPに関する質問のようです
David Brainer

私の間違い..それを正しく読みませんでした
Rene Pot

回答:


339

使用できますArray.sort

次に例を示します。

var arr = [{
    "updated_at": "2012-01-01T06:25:24Z",
    "foo": "bar"
  },
  {
    "updated_at": "2012-01-09T11:25:13Z",
    "foo": "bar"
  },
  {
    "updated_at": "2012-01-05T04:13:24Z",
    "foo": "bar"
  }
]

arr.sort(function(a, b) {
  var keyA = new Date(a.updated_at),
    keyB = new Date(b.updated_at);
  // Compare the 2 dates
  if (keyA < keyB) return -1;
  if (keyA > keyB) return 1;
  return 0;
});

console.log(arr);


17
あなたはkeyA - keyB(またはおそらくkeyB - keyA)使用できませんでしたか?日付オブジェクトにはvalueOf()メソッドがあります。
soktinpk 14

戻るa。updated_at <b。updated_at?1:-1が適しています。日付形式に解析する必要はありません。
oliversisson 2017年

a-b長いコードを避けたい場合は、この機能が非常に重要です。この場合、長いコードが必ずしも悪いわけではありませんが、冗長性により理解が難しくなると思います。現在使用していますvalues.sort((a,b)=>a.attr-b.attr)。配列をソートする必要があるたびに5行を書く必要があるのは面倒です。
AnnanFay

この例は効果的ではなく、多くの不要な計算を行います。並べ替えでは、有効な結果として正または負の数値を使用できます。強制的に1,0、-1にするための追加の計算は不要で、実行ごとに追加の計算を追加するだけです。
パトリックW.マクマホン

偉大thjankワークスます
アンディ・

158

私はここで非常によく似た質問にすでに回答しました:オブジェクトの配列をソートする単純な関数

その質問のために、私はあなたが望むことをするかもしれないこの小さな関数を作成しました:

function sortByKey(array, key) {
    return array.sort(function(a, b) {
        var x = a[key]; var y = b[key];
        return ((x < y) ? -1 : ((x > y) ? 1 : 0));
    });
}


2
これをどうやって元に戻しますか?

4
大文字と小文字を区別しないようにするには、xおよびy変数に.toLowerCase()を追加します
Jacob van Lingen

4
このようなソート機能を逆にするには、結果に-1:)を掛けるだけです
Svish

5
または、出力を取得してarray = array.reverse()関数を使用します。
ルークスティーブンソン

31

Array.sort()メソッドは、代わりに、配列の要素をソートし、配列を返します。Array.sort()不変ではないので注意してください。不変ソートの場合は、immutable- sortを使用してください。

この方法では、現在のupdated_atISO形式で配列を並べ替えます。new Data(iso_string).getTime()ISO時間をUnixタイムスタンプに変換するために使用します。Unixタイムスタンプは、簡単な計算ができる数値です。結果の最初と2番目のタイムスタンプを差し引きます。最初のタイムスタンプが2番目のタイムスタンプより大きい場合、戻り値は正になります。2番目の数値が最初の数値より大きい場合、戻り値は負になります。2つが同じ場合、戻り値はゼロになります。これは、インライン関数に必要な戻り値と完全に一致します。

以下のためのES6

arr.sort((a,b) => new Date(a.updated_at).getTime() - new Date(b.updated_at).getTime());

以下のためのES5

arr.sort(function(a,b){ 
 return new Date(a.updated_at).getTime() - new Date(b.updated_at).getTime();
});

updated_atUNIXタイムスタンプに変更すると、次のようになります。

以下のためのES6

arr.sort((a,b) => a.updated_at - b.updated_at);

以下のためのES5

arr.sort(function(a,b){ 
 return a.updated_at - b.updated_at;
});

この投稿の時点では、最新のブラウザーはES6をサポートしていません。最新のブラウザーでES6を使用するには、babelを使用してコードをES5にトランスパイルします。近い将来、ブラウザでES6がサポートされる予定です。

Array.sort()は、3つの可能な結果のいずれかの戻り値を受け取る必要があります。

  • 正の数(最初の項目> 2番目の項目)
  • 負の数(最初の項目<2番目の項目)
  • 2つのアイテムが等しい場合は0

インライン関数の戻り値は、任意の正または負の数になる可能性があることに注意してください。Array.Sort()は、戻り値が何であるかを気にしません。戻り値が正、負、またはゼロであるかどうかのみが考慮されます。

不変ソートの場合:(ES6の例)

const sort = require('immutable-sort');
const array = [1, 5, 2, 4, 3];
const sortedArray = sort(array);

次のように書くこともできます:

import sort from 'immutable-sort';
const array = [1, 5, 2, 4, 3];
const sortedArray = sort(array);

あなたが見るimport-fromは、ES6にJavaScriptを含めるための新しい方法であり、コードをきれいに見せます。私の個人的なお気に入り。

不変ソートはソース配列を変更せず、新しい配列を返します。const不変データの使用をお勧めします。


19

@David Brainer-Bankersの回答を少し変更したバージョンを次に示します。これは、文字列でアルファベット順に、または数値で数値でソートし、大文字で始まる単語が小文字で始まる単語の上にソートされないようにします(例: "apple、Early"の順序で表示されます)。

function sortByKey(array, key) {
    return array.sort(function(a, b) {
        var x = a[key];
        var y = b[key];

        if (typeof x == "string")
        {
            x = (""+x).toLowerCase(); 
        }
        if (typeof y == "string")
        {
            y = (""+y).toLowerCase();
        }

        return ((x < y) ? -1 : ((x > y) ? 1 : 0));
    });
}

3
提案されたソリューションは、a [key]とb [key]が両方とも文字列でない場合、エラーになる可能性があります。y = y.toLowerCase()をy =( "" + y).toLowerCase()で置き換えることをお勧めします
user8074

sortは、正または負の数値を有効な戻り値として受け入れることができます。あなたはそれを強制的に1,0、-1にするための追加の計算です、-1は必要ありません。単純な戻り値を複雑にします。何も実行しない余分な計算を追加しないことをお勧めします。
Patrick W. McMahon


6

ES2015のサポートにより、次のことが可能になります。

foo.sort((a, b) => a.updated_at < b.updated_at ? -1 : 1)

1
<を-に置き換えて削除する場合、インラインは不要ですか?-1:1"は、有効なリターンを得るでしょう等しくすることができるので、予期しない結果を与えることができる。この例の移動アイテムを同じ項目について0を返す必要がある。。。
パトリック・W・マクマホン

説明していただきありがとうございます
ノーバディ

updated_atがISO時間の場合、これは機能しません。この例では、Unixタイムスタンプを想定していますが、OPはISO形式のデータをポストしました。したがって、比較を行うにはUnixタイムスタンプに変換する必要があります。これはnew Date(iso_str).getTime()Unixタイムスタンプを返すことで実行できます。
Patrick W. McMahon

5

インポートされたデータ

[
    {
        "gameStatus": "1",
        "userId": "c02cfb18-ae66-430b-9524-67d9dd8f6a50",
        "created_at": "2018-12-20 11:32:04"
    },
    {
        "gameStatus": "0",
        "userId": "c02cfb18-ae66-430b-9524-67d9dd8f6a50",
        "created_at": "2018-12-19 18:08:24"
    },
    {
        "gameStatus": "2",
        "userId": "c02cfb18-ae66-430b-9524-67d9dd8f6a50",
        "created_at": "2018-12-19 18:35:40"
    },
    {
        "gameStatus": "0",
        "userId": "c02cfb18-ae66-430b-9524-67d9dd8f6a50",
        "created_at": "2018-12-19 10:42:53"
    },
    {
        "gameStatus": "2",
        "userId": "c02cfb18-ae66-430b-9524-67d9dd8f6a50",
        "created_at": "2018-12-20 10:54:09"
    },
    {
        "gameStatus": "0",
        "userId": "1a2fefb0-5ae2-47eb-82ff-d1b2cc27875a",
        "created_at": "2018-12-19 18:46:22"
    },
    {
        "gameStatus": "1",
        "userId": "7118ed61-d8d9-4098-a81b-484158806d21",
        "created_at": "2018-12-20 10:50:48"
    }
]

昇順の場合

arr.sort(function(a, b){
    var keyA = new Date(a.updated_at),
        keyB = new Date(b.updated_at);
    // Compare the 2 dates
    if(keyA < keyB) return -1;
    if(keyA > keyB) return 1;
    return 0;
});

Asc注文の例

[
    {
        "gameStatus": "0",
        "userId": "c02cfb18-ae66-430b-9524-67d9dd8f6a50",
        "created_at": "2018-12-19 10:42:53"
    },
    {
        "gameStatus": "0",
        "userId": "c02cfb18-ae66-430b-9524-67d9dd8f6a50",
        "created_at": "2018-12-19 18:08:24"
    },
    {
        "gameStatus": "2",
        "userId": "c02cfb18-ae66-430b-9524-67d9dd8f6a50",
        "created_at": "2018-12-19 18:35:40"
    },
    {
        "gameStatus": "0",
        "userId": "1a2fefb0-5ae2-47eb-82ff-d1b2cc27875a",
        "created_at": "2018-12-19 18:46:22"
    },
    {
        "gameStatus": "1",
        "userId": "7118ed61-d8d9-4098-a81b-484158806d21",
        "created_at": "2018-12-20 10:50:48"
    },
    {
        "gameStatus": "2",
        "userId": "c02cfb18-ae66-430b-9524-67d9dd8f6a50",
        "created_at": "2018-12-20 10:54:09"
    },
    {
        "gameStatus": "1",
        "userId": "c02cfb18-ae66-430b-9524-67d9dd8f6a50",
        "created_at": "2018-12-20 11:32:04"
    }
]

降順

arr.sort(function(a, b){
    var keyA = new Date(a.updated_at),
        keyB = new Date(b.updated_at);
    // Compare the 2 dates
    if(keyA > keyB) return -1;
    if(keyA < keyB) return 1;
    return 0;
});

Desc注文の例

[
    {
        "gameStatus": "1",
        "userId": "c02cfb18-ae66-430b-9524-67d9dd8f6a50",
        "created_at": "2018-12-20 11:32:04"
    },
    {
        "gameStatus": "2",
        "userId": "c02cfb18-ae66-430b-9524-67d9dd8f6a50",
        "created_at": "2018-12-20 10:54:09"
    },
    {
        "gameStatus": "1",
        "userId": "7118ed61-d8d9-4098-a81b-484158806d21",
        "created_at": "2018-12-20 10:50:48"
    },
    {
        "gameStatus": "0",
        "userId": "1a2fefb0-5ae2-47eb-82ff-d1b2cc27875a",
        "created_at": "2018-12-19 18:46:22"
    },
    {
        "gameStatus": "2",
        "userId": "c02cfb18-ae66-430b-9524-67d9dd8f6a50",
        "created_at": "2018-12-19 18:35:40"
    },
    {
        "gameStatus": "0",
        "userId": "c02cfb18-ae66-430b-9524-67d9dd8f6a50",
        "created_at": "2018-12-19 18:08:24"
    },
    {
        "gameStatus": "0",
        "userId": "c02cfb18-ae66-430b-9524-67d9dd8f6a50",
        "created_at": "2018-12-19 10:42:53"
    }
]

3

この答えの状態は、使用することができますArray.sort

arr.sort(function(a,b){return new Date(a.updated_at) - new Date(b.updated_at)})

arr = [
    {
        "updated_at" : "2012-01-01T06:25:24Z",
        "foo" : "bar"
    },
    {
        "updated_at" : "2012-01-09T11:25:13Z",
        "foo" : "bar"
    },
    {
        "updated_at" : "2012-01-05T04:13:24Z",
        "foo" : "bar"
    }
];
arr.sort(function(a,b){return new Date(a.updated_at) - new Date(b.updated_at)});
console.log(arr);


2

同じことをするがより短い、もう一つのより数学的な方法:

arr.sort(function(a, b){
    var diff = new Date(a.updated_at) - new Date(b.updated_at);
    return diff/(Math.abs(diff)||1);
});

または滑らかなラムダ矢印スタイルで:

arr.sort((a, b) => {
    var diff = new Date(a.updated_at) - new Date(b.updated_at);
    return diff/(Math.abs(diff)||1);
});

このメソッドは、任意の数値入力で実行できます


過小回答
two7s_clash 2017


2

Typescriptで並べ替え関数を作成しました。これを使用して、オブジェクトの配列内の文字列、日付、数値を検索できます。複数のフィールドでソートすることもできます。

export type SortType = 'string' | 'number' | 'date';
export type SortingOrder = 'asc' | 'desc';

export interface SortOptions {
  sortByKey: string;
  sortType?: SortType;
  sortingOrder?: SortingOrder;
}


class CustomSorting {
    static sortArrayOfObjects(fields: SortOptions[] = [{sortByKey: 'value', sortType: 'string', sortingOrder: 'desc'}]) {
        return (a, b) => fields
          .map((field) => {
            if (!a[field.sortByKey] || !b[field.sortByKey]) {
              return 0;
            }

            const direction = field.sortingOrder === 'asc' ? 1 : -1;

            let firstValue;
            let secondValue;

            if (field.sortType === 'string') {
              firstValue = a[field.sortByKey].toUpperCase();
              secondValue = b[field.sortByKey].toUpperCase();
            } else if (field.sortType === 'number') {
              firstValue = parseInt(a[field.sortByKey], 10);
              secondValue = parseInt(b[field.sortByKey], 10);
            } else if (field.sortType === 'date') {
              firstValue = new Date(a[field.sortByKey]);
              secondValue = new Date(b[field.sortByKey]);
            }
            return firstValue > secondValue ? direction : firstValue < secondValue ? -(direction) : 0;

          })
          .reduce((pos, neg) => pos ? pos : neg, 0);
      }
    }
}

使用法:

const sortOptions = [{
      sortByKey: 'anyKey',
      sortType: 'string',
      sortingOrder: 'asc',
    }];

arrayOfObjects.sort(CustomSorting.sortArrayOfObjects(sortOptions));

1

文字列を日付解析して正しいタイムスタンプを作成できる最新の最良のブラウザにクライアントを制限しない限り、ISO形式の日付によるソートは負荷がかかる可能性があります。

入力が確実で、常にyyyy-mm-ddThh:mm:ssおよびGMT(Z)であることがわかっている場合は、各メンバーから数字を抽出して、整数のように比較できます。

array.sort(function(a,b){
    return a.updated_at.replace(/\D+/g,'')-b.updated_at.replace(/\D+/g,'');
});

日付の形式を変えることができる場合は、isoにチャレンジした人のために何かを追加する必要があるかもしれません:

Date.fromISO: function(s){
    var day, tz,
    rx=/^(\d{4}\-\d\d\-\d\d([tT ][\d:\.]*)?)([zZ]|([+\-])(\d\d):(\d\d))?$/,
    p= rx.exec(s) || [];
    if(p[1]){
        day= p[1].split(/\D/).map(function(itm){
            return parseInt(itm, 10) || 0;
        });
        day[1]-= 1;
        day= new Date(Date.UTC.apply(Date, day));
        if(!day.getDate()) return NaN;
        if(p[5]){
            tz= (parseInt(p[5], 10)*60);
            if(p[6]) tz+= parseInt(p[6], 10);
            if(p[4]== '+') tz*= -1;
            if(tz) day.setUTCMinutes(day.getUTCMinutes()+ tz);
        }
        return day;
    }
    return NaN;
}
if(!Array.prototype.map){
    Array.prototype.map= function(fun, scope){
        var T= this, L= T.length, A= Array(L), i= 0;
        if(typeof fun== 'function'){
            while(i< L){
                if(i in T){
                    A[i]= fun.call(scope, T[i], i, T);
                }
                ++i;
            }
            return A;
        }
    }
}
}

2
使ってみDate.parseませんか?
ロケットハズマット

1

完全を期すために、sortByの可能な一般的な実装を以下に示します。

function sortBy(list, keyFunc) {
  return list.sort((a,b) => keyFunc(a) - keyFunc(b));
}

sortBy([{"key": 2}, {"key": 1}], o => o["key"])

これは、所定の位置でソートする配列のsortメソッドを使用することに注意してください。コピーの場合は、arr.concat()またはarr.slice(0)または同様のメソッドを使用してコピーを作成できます。


1

これで、ソートに使用するキー関数を渡すことができます

Array.prototype.sortBy = function(key_func, reverse=false){
    return this.sort( (a, b) => {
        var keyA = key_func(a),
            keyB = key_func(b);
        if(keyA < keyB) return reverse? 1: -1;
        if(keyA > keyB) return reverse? -1: 1;
        return 0;
    }); 
}

次に、たとえば

var arr = [ {date: "01/12/00", balls: {red: "a8",  blue: 10}},
            {date: "12/13/05", balls: {red: "d6" , blue: 11}},
            {date: "03/02/04", balls: {red: "c4" , blue: 15}} ]

我々はできる

arr.sortBy(el => el.balls.red)
/* would result in
[ {date: "01/12/00", balls: {red: "a8", blue: 10}},
  {date: "03/02/04", balls: {red: "c4", blue: 15}},
  {date: "12/13/05", balls: {red: "d6", blue: 11}} ]
*/

または

arr.sortBy(el => new Date(el.date), true)   // second argument to reverse it
/* would result in
[ {date: "12/13/05", balls: {red: "d6", blue:11}},
  {date: "03/02/04", balls: {red: "c4", blue:15}},
  {date: "01/12/00", balls: {red: "a8", blue:10}} ]
*/

または

arr.sortBy(el => el.balls.blue + parseInt(el.balls.red[1]))
/* would result in
[ {date: "12/13/05", balls: {red: "d6", blue:11}},    // red + blue= 17
  {date: "01/12/00", balls: {red: "a8", blue:10}},    // red + blue= 18
  {date: "03/02/04", balls: {red: "c4", blue:15}} ]   // red + blue= 19
*/

1

Lodashユーティリティライブラリを使用して、この問題を解決できます(非常に効率的なライブラリです)。

const data = [{
    "updated_at": "2012-01-01T06:25:24Z",
    "foo": "bar"
  },
  {
    "updated_at": "2012-01-09T11:25:13Z",
    "foo": "bar"
  },
  {
    "updated_at": "2012-01-05T04:13:24Z",
    "foo": "bar"
  }
]

const ordered = _.orderBy(
  data,
  function(item) {
    return item.updated_at;
  }
);

console.log(ordered)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.min.js"></script>

ここでドキュメントを見つけることができます:https : //lodash.com/docs/4.17.15#orderBy


0

あなたはクロージャーを作成してそれを渡すことができます ここに私の例が働いています

$.get('https://data.seattle.gov/resource/3k2p-39jp.json?$limit=10&$where=within_circle(incident_location, 47.594972, -122.331518, 1609.34)', 
  function(responce) {

    var filter = 'event_clearance_group', //sort by key group name
    data = responce; 

    var compare = function (filter) {
        return function (a,b) {
            var a = a[filter],
                b = b[filter];

            if (a < b) {
                return -1;
            } else if (a > b) {
                return 1;
            } else {
                return 0;
            }
        };
    };

    filter = compare(filter); //set filter

    console.log(data.sort(filter));
});

0
var months = [
    {
        "updated_at" : "2012-01-01T06:25:24Z",
        "foo" : "bar"
    },
    {
        "updated_at" : "2012-01-09T11:25:13Z",
        "foo" : "bar"
    },
    {
        "updated_at" : "2012-01-05T04:13:24Z",
        "foo" : "bar"
    }];
months.sort((a, b)=>{
    var keyA = new Date(a.updated_at),
        keyB = new Date(b.updated_at);
    // Compare the 2 dates
    if(keyA < keyB) return -1;
    if(keyA > keyB) return 1;
    return 0;
});
console.log(months);

0
  • Array.sort()配列のソートに使用します
  • 関数を純粋にするためにスプレッド演算子)を使用して配列を複製する
  • 目的のキー(updated_at)で並べ替え
  • 日付文字列を日付オブジェクトに変換する
  • Array.sort() 不整脈操作を実行できる数値/オブジェクトの場合、現在のアイテムと次のアイテムから2つのプロパティを差し引くことで機能します
const input = [
  {
    updated_at: '2012-01-01T06:25:24Z',
    foo: 'bar',
  },
  {
    updated_at: '2012-01-09T11:25:13Z',
    foo: 'bar',
  },
  {
    updated_at: '2012-01-05T04:13:24Z',
    foo: 'bar',
  }
];

const sortByUpdatedAt = (items) => [...items].sort((itemA, itemB) => new Date(itemA.updated_at) - new Date(itemB.updated_at));

const output = sortByUpdatedAt(input);

console.log(input);
/*
[ { updated_at: '2012-01-01T06:25:24Z', foo: 'bar' }, 
  { updated_at: '2012-01-09T11:25:13Z', foo: 'bar' }, 
  { updated_at: '2012-01-05T04:13:24Z', foo: 'bar' } ]
*/
console.log(output)
/*
[ { updated_at: '2012-01-01T06:25:24Z', foo: 'bar' }, 
  { updated_at: '2012-01-05T04:13:24Z', foo: 'bar' }, 
  { updated_at: '2012-01-09T11:25:13Z', foo: 'bar' } ]
*/

0

私は同じことに直面しているので、私はこれを一般的な理由で処理し、このための関数を作成します:

//example:
//array: [{name: 'idan', workerType: '3'}, {name: 'stas', workerType: '5'}, {name: 'kirill', workerType: '2'}]
//keyField: 'workerType'
// keysArray: ['4', '3', '2', '5', '6']
sortByArrayOfKeys = (array, keyField, keysArray) => {
    array.sort((a, b) => {
        const aIndex = keysArray.indexOf(a[keyField])
        const bIndex = keysArray.indexOf(b[keyField])
        if (aIndex < bIndex) return -1;
        if (aIndex > bIndex) return 1;
        return 0;
    })
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.