SQL でこれを行う方法を考えてみましょう。
SELECT * FROM items INNER JOIN pkgs ON items.id = pkgs.item_id
ORDER BY tobuy DESC, store, aisle, name
次の回答は、JavaScript で内部結合と等結合を実装する方法を示しています。
function equijoin(primary, foreign, primaryKey, foreignKey, select) {
var m = primary.length, n = foreign.length, index = [], c = [];
for (var i = 0; i < m; i++) { // loop through m items
var row = primary[i];
index[row[primaryKey]] = row; // create an index for primary table
}
for (var j = 0; j < n; j++) { // loop through n items
var y = foreign[j];
var x = index[y[foreignKey]]; // get corresponding row from primary
c.push(select(x, y)); // select only the columns you need
}
return c;
}
これで、次のように使用equijoin
して参加できます。items
pkgs
equijoin(items, pkgs, "id", "item_id", function (item, pkg) {
return {
id: +item.id,
tobuy: +item.tobuy,
store: pkg.store,
aisle: +pkg.aisle,
name: item.name
};
});
単項演算子を適用することitem.id
で、 ,item.tobuy
とを数値に強制していることに注意してください。pkg.aisle
+
2 つのテーブルを結合したので、それらを並べ替える必要があります。テーブルを並べ替えるには、組み込みの配列sort
メソッドを使用します。
.sort(function (a, b) {
// ORDER BY tobuy DESC
var aTobuy = a.tobuy, bTobuy = b.tobuy;
if (aTobuy < bTobuy) return 1;
if (aTobuy > bTobuy) return -1;
// ORDER BY store
var aStore = a.store, bStore = b.store;
if (aStore < bStore) return -1;
if (aStore > bStore) return 1;
// ORDER BY aisle
var aAisle = a.aisle, bAisle = b.aisle;
if (aAisle < bAisle) return -1;
if (aAisle > bAisle) return 1;
// ORDER BY name
var aName = a.name, bName = b.name;
if (aName < bName) return -1;
if (aName > bName) return 1;
// keep them unchanged
return a.id - b.id;
});
このsort
メソッドは不安定です(つまり、入力リスト内のソート値が等しい項目の順序が保持されない可能性があります)。したがって、この制限を回避するためにa.id - b.id
、最後のステートメントとして戻ります。
<
また、 andを使用してすべての値 (文字列または数値) を比較していることにも注意してください>
。文字列は辞書式に比較され、数値は数値的に比較されます。
コードをまとめると次のようになります。
var table = equijoin(items, pkgs, "id", "item_id", function (item, pkg) {
return {
id: +item.id,
tobuy: +item.tobuy,
store: pkg.store,
aisle: +pkg.aisle,
name: item.name
};
}).sort(function (a, b) {
var aTobuy = a.tobuy, bTobuy = b.tobuy;
if (aTobuy < bTobuy) return 1;
if (aTobuy > bTobuy) return -1;
var aStore = a.store, bStore = b.store;
if (aStore < bStore) return -1;
if (aStore > bStore) return 1;
var aAisle = a.aisle, bAisle = b.aisle;
if (aAisle < bAisle) return -1;
if (aAisle > bAisle) return 1;
var aName = a.name, bName = b.name;
if (aName < bName) return -1;
if (aName > bName) return 1;
return a.id - b.id;
});
SQLほど簡潔ではありませんか?とにかく、デモをご覧ください: http://jsfiddle.net/7ZG96/
編集:id
、tobuy
および列のみが必要な場合は、次のようname
に並べ替えられたテーブルから抽出できます。map
table.map(function (item) {
return {
id: item.id,
tobuy: item.tobuy,
name: item.name
};
});
これは、次の SQL クエリに対応します。
SELECT id, tobuy, name FROM (SELECT * FROM items INNER JOIN pkgs
ON items.id = pkgs.item_id ORDER BY tobuy DESC, store, aisle, name)
更新されたデモを参照してください: http://jsfiddle.net/7ZG96/1/