どうも。つじけ(tsujikenzo)です。このシリーズでは「オブジェクトにフィルターをかけて抽出しよう」をお届けします。全3回でお送りします。今日は2回目です。
この記事は、#Effective GoogleAppsScriptタグがついております。
前回のおさらい
前回は、「はじめに」ということで、オブジェクト化レコーズとfor in文をお届けしました。
今回は、「反復メソッドによる抽出」をお届けします。
今日のアジェンダ
- 反復メソッドを用いた値による抽出
- 反復メソッドを用いたプロパティによる抽出
- オブジェクト化レコーズのプロパティの抽出
反復メソッドを用いた値による抽出
配列の反復メソッドの1つであるforEach()メソッドは、配列の各要素に処理を行います。
forEach()メソッド内部では、配列のインデックスを使って、外部の配列を順番に呼び出せます。
また、forEach()メソッド内部を改行し、複数の処理を行うこともできます。
const tag = ["A", "B", "C"];
const numbers = [1, 2, 3];
numbers.forEach((number, index) => {
console.log(`${tag[index]} - ${number}`);
console.log();
});
//A - 1
//
//B - 2
//
//C - 3
このテクニックを応用し、オブジェクトの特定の値に該当するプロパティのみを抽出する、という処理ができます。
「抽出する」とは、「新しい空のオブジェクトを作成して、必要な要素を格納していく」というのもポイントです。元のオブジェクトを改変するのではありません。
const member = { id: 1, name: "Tsujike", address: "Hokkaido" };
const keys = Object.keys(member);
const values = Object.values(member);
const newObj = {};
keys.forEach((key, index) => {
if (values[index] === "Tsujike") newObj[key] = values[index];
});
console.log(newObj);//{ name: 'Tsujike' }
if文の条件式は、「オブジェクトの特定の値が含まれないプロパティ」も可能です。
const newObj2 = {};
keys.forEach((key, index) => {
if (values[index] !== "Tsujike") newObj2[key] = values[index];
});
console.log(newObj2); //{ id: 1, address: 'Hokkaido' }
※2023年1月追記
プロパティを指定して抽出する方法その2
オブジェクトを配列に変換してforEach()メソッド、というアプローチのほかに、Object.entries()とObject.fromEntries()というObjectクラスのStaticメソッドで抽出する方法があります。
const member = { id: 1, name: "Tsujike", address: "Hokkaido" };
//指定したプロパティで抽出する
const filterdObject = Object.entries(member).filter(([key]) => key === 'name' || key === 'id');
//配列をオブジェクトに変換する
const newObj = Object.fromEntries(filterdObject);
console.log(newObj); //{ id: 1, name: 'Tsujike' }
削除するプロパティを指定する
削除するプロパティが少ないときは、delete演算子の方がラクなばあいもあるでしょう。
const member = { id: 1, name: "Tsujike", address: "Hokkaido" };
//削除するプロパティを指定する
delete member.address;
console.log(member); //{ id: 1, name: 'Tsujike' }
反復メソッドを用いたプロパティによる抽出
さきほどは、オブジェクトの値でしたが、今回は、オブジェクトのプロパティを条件式にします。
オブジェクトの特定のプロパティに該当するプロパティのみ、抽出してみましょう。
const member = { id: 1, name: "Tsujike", address: "Hokkaido" };
const keys = Object.keys(member);
const values = Object.values(member);
//idプロパティとnameプロパティのみ抽出
const newObj = {};
keys.forEach((key, index) => {
if (key === "name") newObj[key] = values[index];
if (key === "id") newObj[key] = values[index];
});
console.log(newObj); //{ id: 1, name: 'Tsujike' }
これは、このように短絡演算(ショートハンドともいいます)で書き換えることができます。
どちらが可読性が高いかは、ときとばあいによります。(値の列挙は、縦に伸びた方が読みやすいこともあります)
keys.forEach((key, index) => {
if (key === "name" || key === "id") newObj[key] = values[index];
});
同様に、オブジェクトの特定のプロパティに該当しないプロパティのみ、抽出してみましょう。
const newObj2 = {};
keys.forEach((key, index) => {
if (key !== "name") newObj2[key] = values[index];
});
console.log(newObj2); //{ id: 1, address: 'Hokkaido' }
該当しないプロパティが複数あるばいは、このように記述します。
const newObj3 = {};
keys.forEach((key, index) => {
if (key === "name") return;
if (key === "id") return;
newObj3[key] = values[index];
});
console.log(newObj3); //{ address: 'Hokkaido' }
短絡演算でも、記述してみましょう。
const newObj4 = {};
keys.forEach((key, index) => {
if (key === "name" || key === "id") return;
newObj4[key] = values[index];
});
console.log(newObj4); //{ address: 'Hokkaido' }
さまざまな抽出条件の入れ替え
とあるオブジェクトから、必要なプロパティを抽出するとき、以下はおなじ結果を出力します。
- 必要なプロパティをすべて指定する
- 不要なプロパティをすべて指定して否定する
これは、「必要なプロパティがいくつあるのか」によって、最適な処理が異なります。
「かならずこう書けば最適な処理である」という正解がない、プログラミングのむずかしいポイントだと思います。
条件分岐の真偽の入れ替えは、「ド・モルガンの法則」が有名です。ぜひ、学習してみましょう。
オブジェクト化レコーズのプロパティの抽出
いよいよ本題にはいります。
処理順を考えよう
本題にはいるまえに、処理を切り分けて設計していきましょう。
データベースは、データが増えるたびに、下に向かって縦に伸びる原則があります。
なので、先に見出し行を抽出したほうが、そのあとの処理が早いです。
正解はありませんが、この順で設計していいと思います。
プロパティの抽出
前回の復習です。プロパティはこのように抽出しました。
const member = { id: 1, name: "Tsujike", address: "Hokkaido" };
const keys = Object.keys(member);
const values = Object.values(member);
const newObj = {};
keys.forEach((key, index) => {
if (key === "name" || key === "id") newObj[key] = values[index];
});
console.log(newObj);
オブジェクト化レコーズの抽出
forEach()メソッド同様に、配列の各要素を処理して、新しい配列を生成するのが、map()メソッドです。
const tag = ["A", "B", "C"];
const numbers = [1, 2, 3];
const mappedNumbers = numbers.map((number, index) => {
return [`${tag[index]} - ${number}`];
});
console.log(mappedNumbers);
//[ [ 'A - 1' ], [ 'B - 2' ], [ 'C - 3' ] ]
オブジェクト化レコーズの配列に、map()メソッドをぶつけて、内部にプロパティ抽出処理を記述すればOKです。
//オブジェクト化レコーズ
const members = [
{ id: "tg001", name: "Tsujike", address: "Hokkaido" },
{ id: "tg002", name: "Takahashi", address: "Fukuoka" },
{ id: "tg003", name: "Etau", address: "Tokyo" },
];
//必要なプロパティのみ抽出
const filteredProperties = members.map(member => {
const keys = Object.keys(member);
const values = Object.values(member);
const newObj = {};
keys.forEach((key, index) => {
if (key === "name" || key === "id") newObj[key] = values[index];
});
return newObj;
});
console.log(filteredProperties);
//[ { id: 'tg001', name: 'Tsujike' },
// { id: 'tg002', name: 'Takahashi' },
// { id: 'tg003', name: 'Etau' } ]
次回は、応用編です。
まとめ
以上で、「反復メソッドによる抽出」をお届けしました。
配列の反復メソッドを習得すると、ソースコードからfor文を減らし、可読性を高めることができます。
理解が進むにつれて、パズルを解くように、病みつきになりますよ。
次回は、最終回で「配列による反復と抽出」をお届けします。