配列処理の問題集(JavaScript)

17 min read読了の目安(約15800字

はじめに

JavaScriptの配列処理による問題を作成しました。またコードはTypeScriptで書いています。
問題は随時追加予定です!

(追記)
2020/11/14 問題㉑
2020/11/15 問題㉒
2020/11/30 問題㉓
2021/ 5/ 5 問題㉔


問題①

1から100まで格納された配列の作成をして下さい。

解答
const arry = [...new Array(101 - 1).keys()].map((n) => n + 1);
//[...new Array(101 - 1).keys()]だけだと0~99までの配列となるため、mapメソッドで調整

//別解
const array = Array.from({ length: 100 }, (_, i) => i + 1);
//Array.from(arrayLike,mapFn)
//arryLike(配列に変換する配列風オブジェクトまたは反復可能オブジェクト)
//mapFn(配列のすべての要素に対して呼び出される Map 関数。)

問題②

次の連想配列(images)のheightだけを取得し、新しい配列(heights)を作成して下さい。

type Images = {
  height: string;
  width: string;
}[];

const images: Images = [
  { height: "20px", width: "40px" },
  { height: "34px", width: "56px" },
  { height: "28px", width: "64px" },
];

解答
const heights = images.map(({ height }) => {//オブジェクトの分割代入の利用
  return height;
});

//省略記法
const heights = images.map(({ height }) => height);


//別解
const heights = images.reduce((acc, cur, i) => {
  acc[i] = cur.height;
  return acc;
}, []);

問題③

次の連想配列(member)の中から名前(name)の値だけを抜き取った配列が返るような関数getNameを作成して下さい。

type Members = {
  name: string;
  age: number;
  gender: "male" | "female";
}[];

const members: Members = [
  { name: "松井", age: 39, gender: "male" },
  { name: "今田", age: 34, gender: "female" },
  { name: "鈴木", age: 24, gender: "male" },
  { name: "山田", age: 56, gender: "male" },
  { name: "田中", age: 89, gender: "female" },
];

解答
type GetName<T extends Members, U> = (array: T) => U[];

const getName: GetName<Members, string> = (array) => {
  return array.map(({ name }) => name);
};
console.log(getName(members));
//["松井", "今田", "鈴木", "山田", "田中"]

問題④

以下の連想配列(users)の中から、管理者権限(admin)を持っている(true)ユーザーに絞り込み、filteredUsersという変数に格納して下さい。

type Users = {
  id: number;
  admin: Boolean;
}[];

const users: Users = [
  { id: 1, admin: true },
  { id: 2, admin: true },
  { id: 3, admin: false },
  { id: 4, admin: true },
  { id: 5, admin: false },
];
解答
const filteredUsers = users.filter(({ admin }) => admin);
console.log(filteredUsers)
//[
//  { id: 1, admin: true },
//  { id: 2, admin: true },
//  { id: 4, admin: true }
//]

問題⑤

次の多次元配列のインデックス0番目のみを取り出した配列を作成して下さい。

const array = [
  ["Ruffy", "captain"],
  ["Zoro", "combatant"],
];
解答
const arry = array.map((key) => key[0]);
console.log(arry); //["Ruffy", "Zoro"]

問題⑥

次の多次元配列の0番目の配列のみを取り出し新しい配列に作成して下さい。

const array = [
  ["Ruffy", "captain"],
  ["Zoro", "combatant"],
];
解答
const arr = array.filter((key, i) => {
  if (i === 0) {
    return key;
  }
});

//別解
const arr = array.filter((key, index) => index === 0 && key)

console.log(arr); //["Ruffy", "captain"]

問題⑦

次の連想配列(member)の中から35歳以上の名前(name)の値だけを抜き取った配列が返るような関数getNameOver35を作成して下さい。

type Members = {
  name: string;
  age: number;
  gender: "male" | "female";
}[];

const members: Members = [
  { name: "松井", age: 39, gender: "male" },
  { name: "今田", age: 34, gender: "female" },
  { name: "鈴木", age: 24, gender: "male" },
  { name: "山田", age: 56, gender: "male" },
  { name: "田中", age: 89, gender: "female" },
];
解答
type GetNameOver35<T extends Members, U> = (array: T) => U[];

const getNameOver35: GetNameOver35<Members, string> = (array) => {
  return array.filter(({ age }) => age > 35).map(({ name }) => name);
};
console.log(getNameOver35(members));
//["松井", "山田", "田中"]

問題⑧

以下のような重複値を含む配列arrの中から、重複値を除く互いに素な配列を作成して下さい。

const arr = [2, 4, 7, 5, 4];
解答
const coprimeArr = [...new Set(arr)];//[2, 4, 7, 5]

//別解const coprimeArr = arr.filter((num, i, arrr) => {
  return arrr.indexOf(num) === i;
});//[2, 4, 7, 5]

問題⑨

次の連想配列の中からnameプロパティをもったユーザーに絞り込み、getNameという変数に格納して下さい。

interface User {
  id: number;
  name?: string;
}

const users: User[] = [
  { id: 1, name: "豊臣" },
  { id: 2 },
  { id: 3, name: "織田" },
];
解答
const getName = users
  .filter((user: User) => "name" in user)
  
  //別解
  const getName = users.filter(({ name }) => name);

問題⑩

以下の連想配列(users)の中から、管理者権限(admin)を持っている(true)ユーザーを探し、最初に見つけた(true)ユーザーをadminという変数に格納して下さい。

expect: { id: 2, admin: true }

type Users = {
  id: number;
  admin: Boolean;
}[];

const users: Users = [
  { id: 1, admin: false },
  { id: 2, admin: true },
  { id: 3, admin: false },
  { id: 4, admin: true },
  
];
解答
const admin = users.find(({ admin }) => admin);

//別解
const admin = users.filter(({ admin }) => admin)[0]

問題⑪

次の連想配列(member)の中から,田中さんのオブジェクトを抽出するfindTanakaという関数,変数を作成しなさい。

expect: {name: "田中", age: 89, gender: "female"}

type Members = {
  name: string;
  age: number;
  gender: "male" | "female";
}[];

const members: Members = [
  { name: "松井", age: 39, gender: "male" },
  { name: "今田", age: 34, gender: "female" },
  { name: "鈴木", age: 24, gender: "male" },
  { name: "山田", age: 56, gender: "male" },
  { name: "田中", age: 89, gender: "female" },
];
解答
const findTanaka = (array: Members) => {
  return array.find(({ name }) => name === "田中");
};

//別解
const findTanaka = members.members.slice(-1)[0]; 

使用メソッド


問題⑫

アンケートを実施した結果がusersという連想配列に格納されています。ユーザー全員が回答済みかどうかを確認し、hasSubmitted変数に結果(trueかfalse)を示して下さい。

expect: false

type Users = {
  id: number;
  hasSubmitted: boolean;
}[];

const users: Users = [
  { id: 2, hasSubmitted: true },
  { id: 3, hasSubmitted: false },
  { id: 4, hasSubmitted: true },
];

解答
const hasSubmitted = users.every(({ hasSubmitted }) => hasSubmitted);

使用メソッド


問題⑬

次のtripという連想配列に格納されたdistanceの合計を求めて、totalDistanceという変数に格納して下さい。

type Trips = { distance: number }[];

const trips: Trips = [{ distance: 34 }, { distance: 12 }, { distance: 1 }];
解答
const totalDistance = trips.reduce((sum, trip) => {
  return trip.distance + sum;
}, 0);
console.log(totalDistance);//47

//分割代入
const totalDistance = trips.reduce((sum, { distance }) => {
  return distance + sum;
}, 0);
console.log(totalDistance); //47

使用メソッド


問題⑭

次の変数engineersに格納されたエンジニアの種類(フロントエンド、バックエンド)の数を種類を集計し、一つのオブジェクトに格納して下さい。

type Engineers = { type: 'Frontend' | 'Backend' }[]

const engineers: Engineers = [
  { type: 'Frontend' },
  { type: 'Backend' },
  { type: 'Backend' },
  { type: 'Frontend' },
  { type: 'Frontend' },
  { type: 'Backend' },
  { type: 'Backend' }
]

expect: {Frontend: 3, Backend: 4}

解答
const engineerType = engineers.reduce(
  (sum, { type }) => {
    if (type === 'Frontend') {
      sum.Frontend++
    } else {
      sum.Backend++
    }
    return sum
  },
  { Frontend: 0, Backend: 0 }
)

問題⑮

次の変数objを連想配列[{A:'a'},{B:'b'}]にして下さい。

const obj = {
  a: "A",
  b: "B",
};
解答
const arr = Object.entries(obj).map((key) => {
  return { [key[1]]: key[0] };
});

使用メソッド

entries
map


問題⑯

次の変数arrをオブジェクト{a:"0", b:"1"}にして下さい。

const arr = ["a", "b"];
解答
type Alpha = {
  [alpha: string]: string;
};const obj:Alpha = arr.reduce((prev, curr, i) => {
  return { ...prev, [curr]: `${i}` };
}, {});//引数のprevの挙動をコンソール上で確認すると理解が深まります!


問題⑰

次の変数fruitsの中から"みかん"、"ぶどう"をキーに持つオブジェクトのみを抽出し、新しい変数serectFruitsに格納して下さい。

type Fruitsobj = {
  price: number;
  num: number;
};
type Fruits = {
  [fruit: string]: Fruitsobj;
};

const fruits: Fruits = {
  みかん: { price: 200, num: 5 },
  いちご: { price: 400, num: 1 },
  ぶどう: { price: 380, num: 7 },
};
解答
const arr = Object.entries(fruits);
const arrr = arr.filter((key) => {
  return key[0] === "みかん" || key[0] === "ぶどう";
});
const selectFruits = arrr.reduce((prev, [k, v]) => {
  return { ...prev, [k]: v };
}, {});
//ぶどう: {price: 380, num: 7}
//みかん: {price: 200, num: 5}



//別解(class表記)
type Fruits = 'みかん' | 'ぶどう' | 'いちご'

class SelectFruits {
  fruitsArray: [string, Fruitsobj][]
  constructor(
    public allFruits: IFruits,
    public fruit1: Fruits,
    public fruit2: Fruits
  ) {
    this.fruitsArray = Object.entries(this.allFruits)
  }
  filter() {
    this.fruitsArray = this.fruitsArray.filter(
      key => key[0] === this.fruit1 || key[0] === this.fruit2
    )
    return this
  }
  reduce() {
    const selectFruits = this.fruitsArray.reduce((prev, [k, v]) => {
      return { ...prev, [k]: v }
    }, {})
    return selectFruits
  }
}
const orangeAndGrape = new SelectFruits(fruits, 'みかん', 'ぶどう')
console.log(orangeAndGrape.filter().reduce())

問題⑱

次の配列の中で一番大きい値を求めて下さい。

const array = [40, 100, 300, 50];

expect: 300

解答
const result = array.reduce((acc, cur) => {
  return acc > cur ? acc : cur;
});//300

//別解(applyメソッドの利用)
const result1 = Math.max.apply(null, array);

//別解(スプレッド構文の利用)
const result2 = Math.max.(...array);

//別解
function result3(array: number[]) {
  let tempArr = array.sort((a, b) => {
    return a - b;
  });
  let largest = tempArr.pop();
  return largest;
}
console.log(result3(array));//300

問題⑲

次のJsonJson形式の変数complexJsonから"ハンバーグ"の要素だけ取り出し、配列でラップして下さい。

type ComplexJson = {
  [food: string]: { 分類: string; 主成分: string | object };
};

const complexJson: ComplexJson = {
  ハンバーグ: {
    分類: "洋食",
    主成分: "タンパク質",
  },
  カレー: {
    分類: "洋食",
    主成分: {
      ルー: "タンパク質",
      ライス: "炭水化物",
    },
  },
  親子丼: {
    分類: "和食",
    主成分: {: "タンパク質",
      ご飯: "炭水化物",
    },
  },
};

expect [ハンバーグ: {分類: "洋食", 主成分: "タンパク質"}]

解答
const entriesArray = Object.entries(complexJson)const arr = entriesArray.reduce((acc, cur) => {
  if (cur[0] === "ハンバーグ") {
    return [{ ...acc, [cur[0]]: cur[1] }];
  }
  return acc;
}, []);


//別解(クラス記法)
class SelectFood {
  foodArray: [
    string,
    {
      分類: string
      主成分: string | object
    }
  ][]
  constructor(public foodObj: ComplexJson, public food: string) {
    this.foodArray = Object.entries(this.foodObj)
  }
  reduce() {
    this.foodArray = this.foodArray.reduce((acc, cur) => {
      if (cur[0] === 'ハンバーグ') {
        return [{ ...acc, [cur[0]]: cur[1] }]
      }
      return acc
    }, [])
    return this.foodArray
  }
}
const ham = new SelectFood(complexJson, 'ハンバーグ')
console.log(ham.reduce())


問題⑳

次の連想配列のオブジェクトのキー名を"0"→"id"、"1"→"shop"に変更して下さい。

const srcData = [
  { 0: 'id1', 1: '店A' },
  { 0: 'id2', 1: '店B' },
  { 0: 'id3', 1: '店C' }
]

expect: [
{ id: 'id1', shop: '店A' },
{ id: 'id2', shop: '店B' },
{ id: 'id3', shop: '店C' }
]

解答
const newSrcData = srcData.reduce((acc, cur) => {
  return [...acc, { id: cur[0], shop: cur[1] }]
}, []

問題㉑

次の連想配列の果物の詳細が書かれた各オブジェクトから'totalItems'(個数の合計),'cartTotal'(合計金額)をプロパティにもつ連想配列を作成してください。

type Cart = {
  item: string
  price: number
  amount: number
}[]
const cart: Cart = [
  {
    item: 'いちご',
    price: 150,
    amount: 3
  },
  {
    item: 'みかん',
    price: 250,
    amount: 3
  },
  {
    item: 'ぶどう',
    price: 300,
    amount: 2
  }
]

expect: [ { totalItems: 8, cartTotal: 700 } ]

解答
const total = cart.reduce(
  (total, { amount, price }) => {
    total[0]['totalItems'] += amount
    total[0]['cartTotal'] += price
    return total
  },
  [
    {
      totalItems: 0,
      cartTotal: 0
    }
  ]
)

問題㉒

次の1~30までの数字が格納された配列'item'を10分割、14分割した二次元配列'newItems1','newItems2'を作成してください。

const item = Array.from({ length: 30 }, (_, index) => {
  return index + 1;
});
解答
const itemPerPage1 = 10;
const itemPerPage2 = 14;

const pages = (itemPer: number) => {
  return Math.ceil(item.length / itemPer);
};

const newItems1 = Array.from({ length: pages(itemPerPage1) }, (_, index) => {
  const start = index * itemPerPage1;
  const tempItems = item.slice(start, start + itemPerPage1);

  return tempItems;
});

const newItems2 = Array.from({ length: pages(itemPerPage2) }, (_, index) => {
  const start = index * itemPerPage2;
  const tempItems = item.slice(start, start + itemPerPage2);

  return tempItems;
});

console.log(newItems1);//[ [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ], [ 11, 12, 13, 14, 15, 16, 17, 18, 19, 20 ], [ 21, 22, 23, 24, 25, 26, 27, 28, 29, 30 ] ] 
console.log(newItems2);//[ [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 ], [ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28 ], [ 29, 30 ] ] 

//別解
  const chunk = (arr: number[], num: number) => {
    return arr.reduce(
      (a, e, i) =>
        i % num
          ? [...a.slice(0, a.length - 1), [...a[a.length - 1], e]]
          : [...a, [e]],
      []
    )
  }

  console.log(chunk(item, 10))
  console.log(chunk(item, 14))

問題㉓

次の連想配列(member)の中から,鈴木さんを同僚、松井さんと今田さんを後輩として関係を区別してください。

type Members = {
  name: string;
  age: number;
  gender: "male" | "female";
}[];

const members: Members = [
  { name: "松井", age: 21, gender: "male" },
  { name: "今田", age: 23, gender: "female" },
  { name: "鈴木", age: 27, gender: "male" },
  { name: "山田", age: 33, gender: "male" },
  { name: "田中", age: 35, gender: "female" },
];
解答
for (let i = 0; i < members.length; i++) {
  const element = members[i];
  if (element['name'] === '鈴木') {
    console.log(`${element['name']} is my colleague`);//鈴木 is my colleague
    break;//continue であれば山田さん、田中さんのオブジェクトが取れる。
  }
  console.log(`${element['name']} is my junior coworker`);
  //松井 is my junior coworker 
  //今田 is my junior coworker 
}

問題㉔

引数に奇数、偶数を順に受け取り、返り値として自然数を順に並べた配列を返す関数(getNaturalNumber)を作成してください。

console.log(getNaturalNumber([1, 3, 5], [2, 4, 6]))
// [1,2,3,4,5,6]
解答
const getNaturalNumber = (odd: number[], even: number[]) => {
    const NaturalNumber: number[] = []
    while (odd[odd.length - 1] || even[even.length - 1]) {
      // 条件処理における || はどちらか片方が真であれば全体として真を返す
      if (even[even.length - 1]) {
        NaturalNumber.unshift(even.pop())
      }
      if (odd[odd.length - 1]) {
        NaturalNumber.unshift(odd.pop())
      }
    }
    return NaturalNumber
  }
  
  
  //別解(クラス記法)
  class GetNaturalNumber {
  constructor(public odd: number[], public even: number[]) {}

  getNaturalNumber() {
    const num = []

    while (this.odd[this.odd.length - 1] || this.even[this.even.length - 1]) {
      // 条件処理における || はどちらか片方が真であれば全体として真を返す
      if (this.even[this.even.length - 1]) {
        num.unshift(this.even.pop())
      }
      if (this.odd[this.odd.length - 1]) {
        num.unshift(this.odd.pop())
      }
    }
    return num
  }
}
const num = new GetNaturalNumber([1, 3, 5], [2, 4, 6])
console.log(num.getNaturalNumber()) //[1,2,3,4,5,6]