71592


**TypeScriptの連想配列の操作について**

[code]

    data: [ {dataId:1,fruitId:1,name:'りんご',text1:'ひらがな',text2:'果物'},
            {dataId:2,fruitId:1,name:'りんご',text1:'3文字',text2:'赤い'},
            {dataId:1,fruitId:2,name:'オレンジ',text1:'ひらがな',text2:'果物'},
            {dataId:2,fruitId:2,name:'オレンジ',text1:'4文字',text2:'オレンジ色'},
            {dataId:1,fruitId:3,name:'なす',text1:'2文字',text2:'野菜'},
          ]
    
[/code]

上記のような連想配列があるのですが、

[code]

    type Fruit = FruitIndex & {
      fruitDetails: FruitDetail[];
    }
    type FruitIndex ={
      fruitId:number;
      name:string;
      count:number;
    }
    type FruitDetail ={
      text1:string;
      text2:string;
    }
    
    
    const method = (): [number, Fruit[]] => {
    let total = 0;
    //////////////下記を修正したい///////////////////////
    const tmpFruits:Fruit[] = data.map((fruit)=>{
      const fruitDetails:FruitDetail[]=[
        {
          text1:fruit.text1,
          text2:fruit.text2,
        }
      ];
      const count = 1;
      total = count;
    
      return {
        fruitId:fruit.fruitId,
        name:fruit.name,
        fruitDetails,
        count,
      };
    ////////////////////////////////////////////////////
    });
      return [total,tmpFruits];
    }
    const [total,tmpFruits] = method();
    
[/code]

tmpFruitsの結果は

[code]

    {fruitId:1,name:'りんご',count:1,fruitlDetails:[{text1:'ひらがな',text2:'果物'}]},
    {fruitId:1,name:'りんご',count:1,fruitlDetails:[{text1:'3文字',text2:'赤い'}]},
    {fruitId:2,name:'オレンジ',count:1,fruitlDetails:[{text1:'ひらがな',text2:'果物'}]},
    {fruitId:2,name:'オレンジ',count:1,fruitlDetails:[{text1:'4文字',text2:'オレンジ色'}]},
    {fruitId:3,name:'なす',count:1,fruitlDetails:[{text1:'2文字',text2:'野菜'}]},
    
[/code]

となります。

[code]

    totalは1
    
[/code]

となります。

tmpFruitsに求める結果としては

[code]

    {fruitId:1,name:'りんご',count:2,fruitlDetails:[{text1:'ひらがな',text2:'果物'},{text1:'3文字',text2:'赤い'}]},
    {fruitId:2,name:'オレンジ',count:2,fruitlDetails:[{text1:'ひらがな',text2:'果物'},{text1:'4文字',text2:'オレンジ色'}]},
    {fruitId:3,name:'なす',count:1,fruitlDetails:{text1:'2文字',text2:'野菜'}},
    
[/code]

です。

[code]

    totalは5
    
[/code]

です。

また fruitIdは一意・下記を修正したい///の範囲内のみ変更したいです。

かなり初歩的なのですが、よろしくお願い致します。


CC BY-SA 4.0
2020-10-29T09:55:53.940
71589
2020-11-03T05:31:51.860
42358
question
javascript typescript
TypeScriptの連想配列操作


データ構造がちょっと複雑なので`map`や`reduce`を使わず、forEachを使ってみました。

[code]

    interface FruitDetail {
      text1: string;
      text2: string;
    }
    
    interface FruitIndex {
      fruitId: number;
      name: string;
      count: number;
    }
    
    interface InputData extends FruitDetail {
      dataId: number;
      fruitId: number;
      name: string;
    }
    
    interface Fruit extends FruitIndex {
      fruitDetails: FruitDetail[];
    }
    
    const data: InputData[] = [
      { dataId: 1, fruitId: 1, name: "りんご", text1: "ひらがな", text2: "果物" },
      { dataId: 2, fruitId: 1, name: "りんご", text1: "3文字", text2: "赤い" },
      { dataId: 1, fruitId: 2, name: "オレンジ", text1: "ひらがな", text2: "果物" },
      {
        dataId: 2,
        fruitId: 2,
        name: "オレンジ",
        text1: "4文字",
        text2: "オレンジ色",
      },
      { dataId: 1, fruitId: 3, name: "なす", text1: "2文字", text2: "野菜" },
    ];
    
    const method = (): [number, Fruit[]] => {
      // keyをユニークなものを利用すると処理しやすい
      const fruits: { [fruitId: number]: Fruit } = {};
      data.forEach((item) => {
        if (fruits[item.fruitId]) {
          // objectのvalueがない場合
          fruits[item.fruitId].count += 1;
          fruits[item.fruitId].fruitDetails.push({
            text1: item.text1,
            text2: item.text2,
          });
        } else {
          // すでにobjectのvalueが存在する場合
          fruits[item.fruitId] = {
            fruitId: item.fruitId,
            name: item.name,
            count: 1,
            fruitDetails: [
              {
                text1: item.text1,
                text2: item.text2,
              },
            ],
          };
        }
      });
      // totalはdataの長さで良さそう
      // objectのvalueをObject.valuesで取り出すとFruitの配列になる
      return [data.length, Object.values(fruits)];
    };
    
    const [total, tmpFruits] = method();
    
[/code]

※ 余談ですが、型定義の際、`type`よりも`interface`を使うとビルド時のキャッシュが効きます。規模が大きくなったときに差が出ます。

<https://github.com/microsoft/TypeScript/wiki/Performance#preferring-
interfaces-over-intersections>


CC BY-SA 4.0
2020-10-29T10:42:29.600
71592
2020-10-29T10:42:29.600
7997
71589
answer


動作確認例をjsbinに載せました。  
<https://jsbin.com/fajuyabacu/edit?html,js,console>

JSですが、以前、group化するための関数を書いたことがあります。

<https://github.com/standard-
software/partsjs/blob/v9.1.0/source/array/_group.js>  
簡単なコードだと思います。それを使うと、こんな感じで書くことができました。

[code]

    const data = [ {dataId:1,fruitId:1,name:'りんご',text1:'ひらがな',text2:'果物'},
        {dataId:2,fruitId:1,name:'りんご',text1:'3文字',text2:'赤い'},
        {dataId:1,fruitId:2,name:'オレンジ',text1:'ひらがな',text2:'果物'},
        {dataId:2,fruitId:2,name:'オレンジ',text1:'4文字',text2:'オレンジ色'},
        {dataId:1,fruitId:3,name:'なす',text1:'2文字',text2:'野菜'},
      ]
    
    const result = [
    {fruitId:1,name:'りんご',count:2,fruitlDetails:[{text1:'ひらがな',text2:'果物'},{text1:'3文字',text2:'赤い'}]},
    {fruitId:2,name:'オレンジ',count:2,fruitlDetails:[{text1:'ひらがな',text2:'果物'},{text1:'4文字',text2:'オレンジ色'}]},
    {fruitId:3,name:'なす',count:1,fruitlDetails:[{text1:'2文字',text2:'野菜'}]},
    ];
    
    const group = parts.array.group(data, item => item.name);
    const group2 = group.map(item => (
      {
        fruitId:   item[0].fruitId,
        name: item[0].name,
        count: item.length,
        fruitlDetails: item.map(item => ({text1: item.text1, text2: item.text2})),
    
      }
    ))
    
    console.log(
      group2,
      parts.equalDeep(group2, result)
    );
    
[/code]

なすのfruitlDetailsだけ質問が配列になっていなかったので、そこは長さ1の配列にしました。


CC BY-SA 4.0
2020-11-03T05:31:51.860
71688
2020-11-03T05:31:51.860
21047
71589
answer