質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.50%

  • JavaScript

    20369questions

    JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

  • Lodash

    15questions

    Lodashは、JavaScriptのユーティリティライブラリ。Underscoreの派生ライブラリで、配列・オブジェクトの操作に便利です。また、コードの可読性も高めることができます。

js ループ処理の最適化

解決済

回答 3

投稿 編集

  • 評価
  • クリップ 1
  • VIEW 545

tommyTeratail

score 15

 下記コードを 最適化したい

 課題

const list = []; と return list; が見苦しい

_.map() をうまく利用したいが方法が思いつかない

const list = {
  'sports': [
    {
      identify: 'soccer',
      name: 'サッカー',
    },
    {
      identify: 'baseball',
      name: '野球',
    },
  ],
  'nature': [
    {
      identify: 'animal',
      name: '動物',
    },
    {
      identify: 'flower',
      name: '花',
    },
  ],
};

const groups = [
  {identify:'sports', id: 1},
  {identify:'nature', id: 2},
];

const make = (tmpList, groups) => {
  const list = [];
  _.forEach(groups, group => {    
    _.forEach(tmpList[group.identify], v => {
      v['group_id'] = group.id;
      list.push(v);
    });
  });

  return list;
};

console.log(
  make(list, groups)
);
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • turbgraphics200

    2018/02/06 19:30 編集

    ほんとに期待通りなのでしょうか?、提示されたコードを実行すると返されるlistのgroup_idがすべて2になるのですが。

    キャンセル

  • tommyTeratail

    2018/02/06 19:33

    おっしゃる通りですね、 バグです

    キャンセル

  • tommyTeratail

    2018/02/06 19:44

    修正しました。

    キャンセル

回答 3

checkベストアンサー

+1

2次元配列にしてからflattenで1次元配列に叩き落とすか、
reduceで2次元配列→1次元配列に戻しながら格納するかの二択ですね。

こんな感じでいかが?

const make = (tmpList, groups) =>
  _(tmpList)
    .map(tmp =>
      _.map(groups, group => ({...tmp, id: group.id}))
    )
    .flatten()
    .values()

const users = [
  { user: 'barney', age: 36, active: true },
  { user: 'fred',  age: 40, active: false },
  { user: 'travis', age: 37, active: true}
];
const ids = [
  { id: 123 },
  { id: 234 }
];
console.log(make(users, ids));
// いい感じにでました

【おまけ】

reduce使うルートならネイティブJSでも出来そうなのでやりました。

const make = (tmpList, groups) =>
  tmpList
    .map(tmp => groups.map(group => ({...tmp, id: group.id})))
    .reduce((arr, items) => {
      items.forEach(it => { arr.push(it) });
      return arr;
    }, [])

const users = [
  { user: 'barney', age: 36, active: true },
  { user: 'fred',  age: 40, active: false },
  { user: 'travis', age: 37, active: true}
];
const ids = [
  { id: 123 },
  { id: 234 }
];
console.log(make(users, ids));
// こちらもいい感じの結果に

【追記】 グループ分けしたオブジェクトへの対応版

条件変わってますので再度考え直してみます。
まぁ、オブジェクトはtoPairsを使って配列にしてしまえば消化試合です。

キーに引っかかるグループが存在しなかった場合を考慮して、
存在しないグループは一度filterで消し飛ばすというガードも組み込みました。

const list = {
  'sports': [
    {identify: 'soccer', name: 'サッカー'},
    {identify: 'baseball', name: '野球'}
  ],
  'nature': [
    {identify: 'animal', name: '動物'},
    {identify: 'flower', name: '花'}
  ]
};
const groups = [
  {identify:'sports', id: 1},
  {identify:'nature', id: 2},
];

const make = (tmpList, groups) =>
  _(tmpList)
    .toPairs()
    .filter(([gname]) => _.find(groups, group => group.identify === gname))
    .map(([gname, items]) => {
      const group = _.find(groups, group => group.identify === gname);
      return _.map(items, it => ({...it, group_id: group.id}));
    })
    .flatten()
    .value()

result = make(list, groups)

https://codepen.io/travist/full/jrBjBz/にコピペすればちゃんと表示されることがわかります。
結果:

[
   {
      "identify": "soccer",
      "name": "サッカー",
      "group_id": 1
   },
   {
      "identify": "baseball",
      "name": "野球",
      "group_id": 1
   },
   {
      "identify": "animal",
      "name": "動物",
      "group_id": 2
   },
   {
      "identify": "flower",
      "name": "花",
      "group_id": 2
   }
]

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/02/06 18:44

    うぅ、いけると思って未テストだったから動かなかった・・・
    修正して動作確認しました

    キャンセル

  • 2018/02/06 18:47

    ちな、このコードだと名前がbarney、fred、fravisのデータが2件ずつ出来てしまいますが大丈夫ですか?
    しかもID重複してるので正常なデータには思えませんが…
    tmpListだけに単なるテストデータ?

    キャンセル

  • 2018/02/06 19:20

    サンプルコードありがとうございます。
    確かに動かないですが...

    flattenで動作確認してみます

    https://codepen.io/andreic/pen/xpLBz

    キャンセル

  • 2018/02/06 19:48

    提示していただいたコードが、理想の形式です

    キャンセル

  • 2018/02/06 19:54

    修正後コードだとこの手は使えないですね、
    対応版のコード作るのでちょっと待ってくださいね

    キャンセル

  • 2018/02/06 21:44

    回答ありがとうございます

    途中で条件が変わってしまいすみません。
    検証が甘いコードをはっていました。
    何度も回答本当にありがとうございます

    期待通りの回答です。

    pushしてreturnするのは、jsらしくない感じと思っていました。
    新しい考え方を得た気がします

    toPairsばっちりですね

    キャンセル

  • 2018/02/06 21:48

    おまけのほうもありがとうございます

    キャンセル

+1

修正後のコードも、その場しのぎの修正のような気がしてならないのですが、makeが返すlistの値として期待するものは(可読性度外視, Chrome/Firefoxのみ)

const make = (t, g) => g.reduce((a, {identify, id}) => !t[identify].map(i => a[a.push({...i}) - 1].group_id = id) || a, []);  


の結果だと思われますが。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/02/06 21:34

    修正後のコードは、正しいです

    回答ありがとうございます。
    期待通りの動作です。
    魔術のようなコードですね。
    私には難しかったです

    キャンセル

0

回答者はLodashに詳しくありません.


JavaScriptの標準APIを使うとこんな感じでしょうか?
tmpList内のオブジェクトが出力結果配列内に何度も現れるのが気になりますが.

const tmpList = [{v: 1}, {v: 2}];
const groups = [{id: 1}, {id: 2}];
const make = (tmpList, groups) => groups.reduce(
    (prev, curr) => prev.concat(...tmpList.map(v => (v.id = curr.id, v))), //vをクローンしたほうが良いのかも
    []
);
console.log(make(tmpList, groups));

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/02/06 19:27

    LodashのforEachはオブジェクトを受けるので, これだと駄目だね

    キャンセル

  • 2018/02/06 21:37

    回答ありがとうございます。

    > vをクローンしたほうが良いのかも
    可能であれば理由がしりたいです。

    キャンセル

  • 2018/02/06 22:08

    誤った前提でのコード・コメントなので, お気になさらず. (言外に元のコードバグってね?という意図がありました)

    キャンセル

  • 2018/02/06 22:13

    質問したコードが検証甘かったのでご迷惑おかけしました。
    協力ありがとうございます。

    キャンセル

同じタグがついた質問を見る

  • JavaScript

    20369questions

    JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

  • Lodash

    15questions

    Lodashは、JavaScriptのユーティリティライブラリ。Underscoreの派生ライブラリで、配列・オブジェクトの操作に便利です。また、コードの可読性も高めることができます。