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

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

ただいまの
回答率

89.53%

JavaScript 配列 重複した列を足して返したい

解決済

回答 5

投稿

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

zeeee

score 1

前提・実現したいこと

JavaScriptで配列の変換をしたい

該当のソースコード

最初の配列

let data = [["a","b",10],["a","b",20],["a","c",30],["a","c",40],["a","d",50]];

結果

[["a","b",30],["a","c",70],["a","d",50];

data[0]とdata[1]が一致した時に,data[2]を足した配列を返したいです。

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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

回答 5

+2

すでにベストアンサーが決まった後に失礼します。

考え方

この回答では、考え方として以下の1.〜 4. の考え方によるアプローチを採ります。

1.説明の便宜上、data の要素である配列(例: ["a","b",10] )について、
・末尾の要素を除いた配列(例: ["a", "b"] )を、キー配列と呼ぶ。
・末尾の要素(例: 10) のことを、単に 数値 と呼ぶ。

2.所与の data から、まず以下の2点を作成
(ⅰ)totals:各キー配列別の数値の合計が格納されたオブジェクト
(ⅱ)keys : data の要素に出現するキー配列を、出現順に、かつ、重複なく含む配列

3.上記2.(ⅰ)のオブジェクト totals には、キー配列が例えば ["a", "b"] である数値の合計(ご質問にあるサンプルだと 30)が  totals.a.b  に格納されるようにする。
・従って、ご質問の例だと、 totals は以下のようなオブジェクトになる。

// totals の例
{ a: { b: 30, c: 70, d: 50 } }

4.オブジェクト totals と keys から、結果として望ましい形式の配列 result を得る。

コード例

以下は、上記の考え方によるコードです。配列やオブジェクトの操作で便利なライブラリ lodash を使用しています。

const [totals, keys] = data.reduce(([obj, keys], ary) => {
  const [k, v] = [_.initial(ary), _.last(ary)];
  if (_.has(obj, k)) {    
    _.set(obj, k, _.get(obj, k) + v);
  }
  else {
    _.set(obj, k, v);
    keys.push(k);
  }
  return [obj, keys];
}, [{}, []]);

const result = keys.map(k => [...k, _.get(totals, k)]);


上記のコードで使っている lodash のメソッドは以下です。

  • totalsのキー配列に対する値の取得、設定および存在確認:  _.get_.set_.has 

  • 配列から最後の要素を取得:  _.last 

  • 配列から最後の要素を除いた配列の取得:  _.initial

以下は、上記のコードを動作確認するためのサンプルです。動作確認のため、dataに要素を追加しています。

以上、参考になれば幸いです。

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

+1

const data = [["a","b",10],["a","b",20],["a","c",30],["a","c",40],["a","d",50]];
const o = data.reduce((a,c)=> a[c[0]] ? (a[c[0]][c[1]] ? {...a, [c[0]]:{...a[c[0]],[c[1]]: a[c[0]][c[1]] + c[2]} }: {...a, [c[0]]:{...a[c[0]],[c[1]]:c[2]}}) : {...a, [c[0]]:{[c[1]]:c[2]} },{});
const p = Object.keys(o).reduce((a,c) => a.concat([Object.keys(o[c]).map(e=>[c,e,o[c][e]])]),[]);
console.log(p);


group をつくって、展開すると考えました。

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

+1

new Map()と分割代入の練習で作ってみました。

let data = [["a", "b", 10], ["a", "b", 20], ["a", "c", 30], ["a", "c", 40], ["a", "d", 50], ["a", "b", "c", 50], ["a", "b", "c", 50]];
//[["a","b",30],["a","c",70],["a","d",50];

const aggregate = new Map();
data.forEach(keys_value => {
    const value_keys = Array.from(keys_value);
    value_keys.unshift(value_keys.pop());
    const [value, ...keys] = [...value_keys];
    aggregate.set(JSON.stringify(keys), (aggregate.get(JSON.stringify(keys)) || 0) + value);
});

const result = [...aggregate.entries()].map(v => [...JSON.parse(v[0]), v[1]]); //[ [ "a", "b", 30 ], [ "a", "c", 70 ], [ "a", "d", 50 ], [ "a", "b", "c", 100 ] ]
console.log(result);
 [ [ 'a', 'b', 30 ],
  [ 'a', 'c', 70 ],
  [ 'a', 'd', 50 ],
  [ 'a', 'b', 'c', 100 ] ]

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

checkベストアンサー

0

複雑なので綺麗に収まりませんね。

const data = [
  ["a","b",10],
  ["a","b",20],
  ["a","c",30],
  ["a","c",40],
  ["a","d",50]
];
const result = Object.entries(
  data
    .map(([k1, k2, num]) => [`${k1}.${k2}`, num])
    .reduce((o, [k, num]) => ({...o, [k]: (o[k] || 0) + num}), {})
).map(([key, num]) => [...key.split('.'), num]);

console.log(JSON.stringify(result, null, 2));
[
  [
    "a",
    "b",
    30
  ],
  [
    "a",
    "c",
    70
  ],
  [
    "a",
    "d",
    50
  ]
]

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2020/03/27 14:41

    文字列の連結で処理するのは微妙ですね
    セパレータを予約語としてきちんと仕様提示しないと
    バグに繋がります

    キャンセル

  • 2020/03/27 14:59

    そうですね、プロの現場なら確実に共有・確認しておくべき事項ですね。
    私はキー情報候補になる文字列には`.`は使わないみたいなローカルルールを付与することが多いですかね。

    `["a", "b"] === ["a", "b"]`の結果が`false`になるような言語ですし、
    ガチで作るなら修正欄で死ぬほど詰めまくる必要があります。

    じゃあ最初から回答するなよみたいな感じになりますので、
    質問文の状況から必要最小限のコードで良いんじゃない?くらいに考えて回答に起こしました。

    キャンセル

  • 2020/03/27 15:03

    微妙なだけで絶対ダメとは思いません。
    「配列内にピリオドを含む文字を入れてはいけません」
    と注記があれば大丈夫でしょう。
    もしくはなんらかのセパレータをユーザーが指定できるようにするとか
    調整次第ですかね・・・

    キャンセル

0

思ったよりグダグダになったので、最適解は他の回答者におまかせします

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2020/03/27 12:57

    var data = [["a","b",10],["a","b",20],["a","c",30],["a","c",40],["a","d",50]];
    var res=[...data.reduce((x,y)=>(x.add(JSON.stringify([y[0],y[1]])),x),new Set())]
    .map(x=>JSON.parse(x))
    .map(x=>[x[0],x[1],data.filter(y=>x[0]==y[0]&&x[1]==y[1]).reduce((x,y)=>x+y[2],0)]);
    console.log(res);

    キャンセル

  • 2020/03/27 12:58

    あとa,bとb,aが一緒かどうかでも結果は変わってきます

    キャンセル

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

  • ただいまの回答率 89.53%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる