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

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

新規登録して質問してみよう
ただいま回答率
85.50%
JavaScript

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

TypeScript

TypeScriptは、マイクロソフトによって開発された フリーでオープンソースのプログラミング言語です。 TypeScriptは、JavaScriptの構文の拡張であるので、既存の JavaScriptのコードにわずかな修正を加えれば動作します。

Q&A

解決済

7回答

4806閲覧

配列をマージしつつ、重複を取り除く方法

os1_nmnm

総合スコア12

JavaScript

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

TypeScript

TypeScriptは、マイクロソフトによって開発された フリーでオープンソースのプログラミング言語です。 TypeScriptは、JavaScriptの構文の拡張であるので、既存の JavaScriptのコードにわずかな修正を加えれば動作します。

0グッド

3クリップ

投稿2019/01/28 03:55

編集2019/01/28 05:31

連想配列が入った配列が2つあり、idの重複を除いてマージする必要があります。
そのため、下記の通り処理しました。

typescript

1const member1 = [ 2 { id: 1, name: 'john' }, 3 { id: 2, name: 'paul' }, 4 { id: 3, name: 'george' }, 5 { id: 4, name: 'ringo' } 6]; 7 8const member2 = [ 9 { id: 1, name: 'john' }, 10 { id: 5, name: 'mick' }, 11 { id: 6, name: 'jimi' }, 12 { id: 7, name: 'mike' } 13]; 14 15const mergedMembers = member1.concat(member2); 16const result = [...mergedMembers] 17 .filter((member, index, self) => self.findIndex(s => member.id === s.id) === index); 18console.log(result);

他のアプローチがあれば、ご教授いただけますと幸いです。
(なるべくスマートな方法が嬉しいです)

追記

出力結果について
出力結果の配列の順序にこだわりはありません。

改善したいポイント
ワンライナーで処理したことによって可読性がやや低く感じるので、これを改善したい。

気になる質問をクリップする

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

m.ts10806

2019/01/28 04:01

このコードも随分スマートに思いましたが(個人の感想です)、どのような問題があるのでしょうか。 アンケート的なものや実際に課題や問題がないものですと非推奨になってしまいます。 回答の方向性や実際の課題を明示してください。
maisumakun

2019/01/28 04:09

出力結果の配列の順序は今のものと揃えたほうがいいですか、それとも特にこだわりはありませんか?
guest

回答7

0

ベストアンサー

JavaScript

1const mergedMembers = member1.concat(member2); 2const result = [...mergedMembers]

この部分、
concatを使ってから展開するくらいなら、最初からこのように書きましょう。

JavaScript

1const result = [...member1, ...member2]

filterはindex値の管理が煩雑になるので、
reduceを使って全上書き構想にした方が実装しやすいと思います。

リーダブルコードに書いてある内容ですが、
読むのに必要な時間を最小にすることが読みやすいコードなので、
filterであれこれ頑張って強引に1行にするより、reduceを使った方が良いかも?

JavaScript

1const member1 = [ 2 { id: 1, name: 'john' }, 3 { id: 2, name: 'paul' }, 4 { id: 3, name: 'george' }, 5 { id: 4, name: 'ringo' } 6]; 7const member2 = [ 8 { id: 1, name: 'john' }, 9 { id: 5, name: 'mick' }, 10 { id: 6, name: 'jimi' }, 11 { id: 7, name: 'mike' } 12]; 13 14var tmp = [...member1, ...member2] 15 .reduce((obj, it) => { 16 obj[it.id] = it; 17 return obj; 18 }, {}); 19const result = Object.values(tmp);

まぁ、そもそもネイティブのJSは機能が圧倒的に足りていないので、
スマート言うなら最初からLodash使えというシンプルな話になります。
_.uniqByで一撃なので論じるまでもありません。

JavaScript

1const result = _.uniqBy([...member1, ...member2], 'id');

投稿2019/01/28 05:09

編集2019/01/28 05:23
miyabi-sun

総合スコア21158

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

Mapで保管して重複除去、という方法も考えられます(iteratorが必要なので、IEでは動きません)。

javascript

1// 今と順序は変わるけど、簡潔に済ませる 2const map = new Map; 3 4member1.concat(member2).forEach(item => map.set(item.id, item)); 5const result = [...map.values()];

投稿2019/01/28 04:12

maisumakun

総合スコア145121

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

member1, member2 にはそれぞれ重複がないと仮定しますが、 member2 から member1 に含まれる id を取り除いた配列を連結させてもいいと思います。

js

1const result = member1.concat(member2.filter(m2 => 2 ! member1.map(m1 => m1.id).includes(m2.id) 3)); 4console.log(result);

投稿2019/01/28 04:27

編集2019/01/28 04:41
mather

総合スコア6753

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

フォーマットは変わりますが、idをキーとする Map を使うのがスマートと思います。

JavaScript

1member1.concat(member2).reduce((map, user) => (map.set(user.id, user.name), map), new Map);

外出先につき、コードは未検証なのでケアレスミスがあるかもしれませんが、参考までに。
先に存在した要素を優先させる場合は Map#has で分岐させます。

Re; os1_nmnm さん

投稿2019/01/28 04:21

think49

総合スコア18156

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

think49

2019/01/28 04:22

回答が重複してしまいました。
guest

0

idだけみればいいなら

javascript

1const member1 = [ 2 { id: 1, name: 'john' }, 3 { id: 2, name: 'paul' }, 4 { id: 3, name: 'george' }, 5 { id: 4, name: 'ringo' } 6]; 7 8const member2 = [ 9 { id: 1, name: 'john' }, 10 { id: 5, name: 'mick' }, 11 { id: 6, name: 'jimi' }, 12 { id: 7, name: 'mike' } 13]; 14var m=member1.concat(member2.filter(function(x){ 15 return member1.map(function(x){ 16 return x.id; 17 }).indexOf(x.id)<0; 18})); 19 20console.log(m);

投稿2019/01/28 04:22

yambejp

総合スコア114572

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

こちらはどうでしょう?

JavaScript

1const result = [...member1, ...member2] 2 .reduce((acc, {id, name}) => (acc[id] = acc[id] || name, acc), []) 3 .reduce((acc, name, id) => [...acc, {id, name}], []); 4console.log(result);

.
もうひとつ思いついたので追記します。

JavaScript

1const memo = []; 2const result = [...member1, ...member2] 3 .reduce((acc, {id, name}) => memo[id] 4 ? acc // メモ済みのIDだったらaccに追加しないで飛ばす 5 : (memo[id] = true, [...acc, {id, name}]) // 初出のIDならメモして、追加 6 , []); 7console.log(result);

投稿2019/01/29 12:16

編集2019/01/31 18:41
shinji709

総合スコア805

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

setを使ってみてはどうですか?
distinctでもいいかもしれません。

投稿2019/01/28 04:03

編集2019/01/28 04:07
Nippun

総合スコア1147

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

papinianus

2019/01/28 04:08

オブジェクトを要素とすることが主な用途であることからすると、Setでは対応できないのでは(別物と判定してくれない)?
think49

2019/01/29 12:25

あえて、Setを使うなら、JSON化したString値を格納でしょうか。 ただし、id値の重複において、name値も重複していないと重複判定で漏れてしまうデメリットがあります。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問