Python 3 エンジニア認定基礎試験 データ構造 問題

ゆめさくが作った練習問題です。本試験の問題ではありません。

データ構造の問題を1⁠8問、小分野ごとにまとめました。選ぶと、その場で正誤と解説が出ます。

ログインなしで解けます。答えはこのブラウザの中だけに残り、どこにも送りません。

この分野の小分野

  • リストとタプルと集合(9問)
  • 辞書とループの技法と比較(9問)

データ構造の問題

18 問

選ぶと、すぐに正誤と解説が出ます。選んだ答えは変えられません。

  1. リストとタプルと集合

    問 1a = [1, 2] に a.append([3, 4]) を実行した場合と、a.extend([3, 4]) を実行した場合の、それぞれの a の要素数の組み合わせとして正しいものはどれですか。

  2. 問 2リストの sort() メソッドを呼び出したときの戻り値として正しいものはどれですか。

  3. 問 3次のコードを実行したときの出力として正しいものはどれですか。

    a = ['x', 'y', 'z']
    a.insert(1, 'w')
    v = a.pop()
    print(a, v)
  4. 問 4次のコードを実行したときの出力として正しいものはどれですか。

    s = ['a', 'b', 'a', 'c', 'a']
    print(s.index('a', 1), s.count('a'))
  5. 問 5先に入れた要素から順に取り出すキュー (先入れ先出し) を効率よく実装する方法として、チュートリアルが勧めているものはどれですか。

  6. 問 6次のコードを実行したときの出力として正しいものはどれですか。

    pairs = [x * 10 + y for x in range(1, 3) for y in range(3) if x != y]
    print(pairs)
  7. 問 7リスト a の要素を取り除く del a[i] と a.pop(i) の違いとして正しいものはどれですか。

  8. 問 8次のコードを実行したときの出力として正しいものはどれですか。

    t = 10, [1, 2]
    x, y = t
    y.append(3)
    print(t)
  9. 問 9次のコードを実行したときの出力として正しいものはどれですか。

    s = {}
    t = {c for c in 'level'} - set('vow')
    print(type(s).__name__, sorted(t))
  10. 辞書とループの技法と比較

    問 10辞書のキーとして使えず、使おうとすると TypeError になるものはどれですか。

  11. 問 11次のコードを実行したときの出力として正しいものはどれですか。

    pairs = [('a', 1), ('b', 2), ('a', 3)]
    d = dict(pairs)
    print(d)
  12. 問 12次のコードを実行したときの出力として正しいものはどれですか。

    d = {'b': 1, 'c': 2, 'a': 3}
    print(list(d), sorted(d), 3 in d)
  13. 問 13シーケンスをループするとき、各要素のインデックスと要素を同時に取り出せる組み込み関数はどれですか。

  14. 問 14list(zip(['a', 'b', 'c'], [1, 2])) の結果として正しいものはどれですか。

  15. 問 15シーケンスを並べ替えた順でループするときに使う組み込み関数 sorted() の説明として正しいものはどれですか。

  16. 問 16次のコードを実行したときの出力として正しいものはどれですか。

    a = [1, 2, 2, 3]
    for x in a:
        if x == 2:
            a.remove(x)
    print(a)
  17. 問 17次のコードを実行したときの出力として正しいものはどれですか。

    x = 0 or [] or 'ok'
    y = 'a' and '' and 'b'
    print(x, repr(y))
  18. 問 18次のコードを実行したときの出力として正しいものはどれですか。

    print((1, 2) < (1, 2, -1), [3] < [2, 9], 1 < 3 > 2)

18 問中 0 問に答えました

解説の一覧

解いたあとに読み返せるよう、全問の解説を並べています。問いを開くと解説が出ます。

リストとタプルと集合

問1a = [1, 2] に a.append([3, 4]) を実行した場合と、a.extend([3, 4]) を実行した場合の、それぞれの a の要素数の組み合わせとして正しいものはどれですか。

正解は「append は 3 個、extend は 4 個」です。append は渡された値をそのまま 1 つの要素として末尾に足します。リスト [3, 4] を渡すと、そのリスト自体が 1 つの要素になり、a は [1, 2, [3, 4]] で要素数は 3 です。extend は渡されたイテラブルの要素を 1 つずつ末尾に足すので、a は [1, 2, 3, 4] で要素数は 4 です。「両方 4 個」は append も中身をばらして足すと考えた誤りです。「append 4 個、extend 3 個」は 2 つのメソッドの役目を逆に覚えた誤りです。「両方 3 個」は extend もリストを 1 つの要素として足すと考えた誤りです。 出典 https://docs.python.org/ja/3/tutorial/datastructures.html#more-⁠on-⁠lists

問2リストの sort() メソッドを呼び出したときの戻り値として正しいものはどれですか。

正解は「None」です。sort() はリストをその場で (インプレースで) 並べ替えるメソッドで、戻り値は None です。チュートリアルは、insert や remove や sort のようにリストを変更するだけのメソッドはデフォルトの None を返し、これは変更可能なデータ構造全体の設計上の原則だと説明しています。このため b = a.sort() と書くと b には None が入ります。「新しいリスト」を返すのは組み込み関数 sorted() のほうです。「元のリスト自身」を返すことはなく、print(a.sort()) は None と表示します。「要素の個数」を返すメソッドではありません。 出典 https://docs.python.org/ja/3/tutorial/datastructures.html#more-⁠on-⁠lists

問3次のコードを実行したときの出力として正しいものはどれですか。
a = ['x', 'y', 'z']
a.insert(1, 'w')
v = a.pop()
print(a, v)

正解は「['x', 'w', 'y'] z」です。insert の第 1 引数はインデックスで、そのインデックスにある要素の直前に挿入します。a.insert(1, 'w') は 'y' の直前に入るので a は ['x', 'w', 'y', 'z'] になります。次に引数なしの pop() は末尾の要素を取り除いて返すので、v は 'z'、a は ['x', 'w', 'y'] です。「['x', 'y', 'w'] z」はインデックス 1 の直後に入ると考えた誤りです。「['w', 'x', 'y'] z」は先頭に入ると考えた誤りで、先頭に入れるのは insert(0, x) です。「None」の選択肢は pop も None を返すと考えた誤りで、pop は取り除いた値を返します。 出典 https://docs.python.org/ja/3/tutorial/datastructures.html#more-⁠on-⁠lists

問4次のコードを実行したときの出力として正しいものはどれですか。
s = ['a', 'b', 'a', 'c', 'a']
print(s.index('a', 1), s.count('a'))

正解は「2 3」です。index(value, start) は start の位置から探し始めますが、返すのはリスト全体の先頭から数えた位置です。s の 'a' は位置 0、2、4 にあり、位置 1 から探すと最初に見つかるのは位置 2 なので 2 です。count('a') はリストの中に 'a' が現れる回数を返すので 3 です。「1 3」は start からの相対位置 (2 - 1) が返ると考えた誤りです。「0 3」は start を無視して最初の位置を返すと考えた誤りです。「2 2」は count も start 以降だけを数えると考えた誤りで、count に探す範囲の指定はありません。 出典 https://docs.python.org/ja/3/tutorial/datastructures.html#more-⁠on-⁠lists

問5先に入れた要素から順に取り出すキュー (先入れ先出し) を効率よく実装する方法として、チュートリアルが勧めているものはどれですか。

正解は「collections.deque を使い popleft() で取り出す」です。リストの末尾での追加や取り出しは速いのですが、先頭での挿入や取り出しは、ほかのすべての要素を 1 つずつずらす必要があるので遅くなります。そこでチュートリアルは、両端での追加と取り出しが速くなるように設計された collections.deque を使い、append で入れて popleft で取り出す方法を示しています。pop(0) は動きますが先頭の取り出しで全要素がずれるので効率がよくありません。insert(0, x) も先頭への挿入で同じ問題があります。タプルは変更できず、切り落とすたびに新しいタプルを作るので向きません。 出典 https://docs.python.org/ja/3/tutorial/datastructures.html#using-⁠lists-⁠as-⁠queues

問6次のコードを実行したときの出力として正しいものはどれですか。
pairs = [x * 10 + y for x in range(1, 3) for y in range(3) if x != y]
print(pairs)

正解は「[1⁠0, 1⁠2, 2⁠0, 2⁠1]」です。内包表記に for と if が複数あるときは、左から順に入れ子にした for 文と if 文と同じ順で評価されます。外側の x が 1 のとき y は 0、1、2 と回り、x != y を満たす 0 と 2 から 1⁠0 と 1⁠2 ができます。x が 2 のときは 0 と 1 が条件を満たし 2⁠0 と 2⁠1 ができるので、[1⁠0, 1⁠2, 2⁠0, 2⁠1] です。「[1⁠0, 2⁠0, 1⁠2, 2⁠1]」は後ろの for が外側になると考えた誤りです。6 個の選択肢は if の条件を読み落とした誤りです。入れ子のリストは、内包表記の中にさらに内包表記を書いたときにできる物で、for を 2 つ並べただけでは平らなリストになります。 出典 https://docs.python.org/ja/3/tutorial/datastructures.html#list-⁠comprehensions

問7リスト a の要素を取り除く del a[i] と a.pop(i) の違いとして正しいものはどれですか。

正解は「del は値を返さないが pop は取り除いた値を返す」です。del 文はインデックスを指定して要素を取り除きますが、pop() メソッドと違って値を返しません。文なので x = del a[0] のように式の中で使うこともできません。一方 pop(i) は位置 i の要素を取り除き、その値を返します。「del が値を返す」は逆の覚え違いです。スライスについても逆で、del a[1:3] のように del はスライスを取り除けますが、pop はインデックスを 1 つだけ受け取ります。値で指定して取り除くのは remove(x) で、del も pop もインデックスで指定します。 出典 https://docs.python.org/ja/3/tutorial/datastructures.html#the-⁠del-⁠statement

問8次のコードを実行したときの出力として正しいものはどれですか。
t = 10, [1, 2]
x, y = t
y.append(3)
print(t)

正解は「(1⁠0, [1, 2, 3])」です。t = 1⁠0, [1, 2] は丸括弧がなくてもタプルのパックで、t は (1⁠0, [1, 2]) です。x, y = t はシーケンスのアンパックで、x に 1⁠0、y に t の 2 番目の要素であるリストそのものが入ります。y.append(3) はそのリストを変更するので、t の中から見えるリストも [1, 2, 3] になります。「(1⁠0, [1, 2])」はアンパックでリストが写されると考えた誤りで、y と t[1] は同じオブジェクトです。タプルの要素への代入はできませんが、タプルが持つ変更可能なリストの中身は変えられるので TypeError にはなりません。表示は丸括弧のタプルのままで、リストにはなりません。 出典 https://docs.python.org/ja/3/tutorial/datastructures.html#tuples-⁠and-⁠sequences

問9次のコードを実行したときの出力として正しいものはどれですか。
s = {}
t = {c for c in 'level'} - set('vow')
print(type(s).__name__, sorted(t))

正解は「dict ['e', 'l']」です。空の波括弧 {} が作るのは空の集合ではなく空の辞書なので、type(s).__name__ は dict です。空の集合は set() で作ります。t は集合の内包表記で、'level' の文字から重複を除いた {'l', 'e', 'v'} ができ、そこから set('vow') すなわち {'v', 'o', 'w'} を引いた差集合は {'e', 'l'} です。sorted で並べると ['e', 'l'] です。「set」で始まる 2 つは {} を空の集合と考えた誤りです。'e' や 'l' が 2 回ずつ出る選択肢は、集合が重複を持たないことを読み落とした誤りです。 出典 https://docs.python.org/ja/3/tutorial/datastructures.html#sets

辞書とループの技法と比較

問10辞書のキーとして使えず、使おうとすると TypeError になるものはどれですか。

正解は「('a', [1])」です。辞書のキーには変更できない型の値を使います。文字列と数値は常にキーにでき、タプルは文字列や数値やほかのタプルだけを含むならキーにできます。しかし、直接または間接に変更可能なオブジェクトを含むタプルはキーにできません。('a', [1]) はリストを含むので、d[('a', [1])] = 0 は TypeError になります。(1, 'a') は数値と文字列だけのタプルなのでキーにできます。'key' は文字列、3.5 は数値なので、どちらもそのままキーにできます。 出典 https://docs.python.org/ja/3/tutorial/datastructures.html#dictionaries

問11次のコードを実行したときの出力として正しいものはどれですか。
pairs = [('a', 1), ('b', 2), ('a', 3)]
d = dict(pairs)
print(d)

正解は「{'a': 3, 'b': 2}」です。dict() にキーと値のペアのシーケンスを渡すと、そのペアから辞書を作ります。ペアは前から順に入るので、まず 'a' に 1、'b' に 2 が入り、最後の ('a', 3) で 'a' の値が 3 に置き換わります。すでに使われているキーで値を記憶すると、前の値は忘れられるためです。キーの並びは最初に入った順のままなので {'a': 3, 'b': 2} です。「{'a': 1, 'b': 2}」は最初の値が残ると考えた誤りです。値をリストにまとめる働きは dict() にはありません。キーが重なってもエラーにはならず、ValueError にもなりません。 出典 https://docs.python.org/ja/3/tutorial/datastructures.html#dictionaries

問12次のコードを実行したときの出力として正しいものはどれですか。
d = {'b': 1, 'c': 2, 'a': 3}
print(list(d), sorted(d), 3 in d)

正解は「['b', 'c', 'a'] ['a', 'b', 'c'] False」です。辞書に list(d) を使うと、全てのキーを、キーが挿入された順に並べたリストが返ります。d は 'b'、'c'、'a' の順に作ったので ['b', 'c', 'a'] です。並べ替えたキーが欲しいときは sorted(d) を使い、['a', 'b', 'c'] になります。in は値ではなくキーがあるかを調べるので、3 in d は False です。1 つめの選択肢は list(d) がキーを並べ替えると考えた誤りです。「True」の選択肢は in が値を調べると考えた誤りです。「[1, 2, 3]」は list(d) が値を並べると考えた誤りで、値が欲しいときは list(d.values()) と書きます。 出典 https://docs.python.org/ja/3/tutorial/datastructures.html#dictionaries

問13シーケンスをループするとき、各要素のインデックスと要素を同時に取り出せる組み込み関数はどれですか。

正解は「enumerate()」です。enumerate() をシーケンスに使うと、ループのたびにインデックスと要素の組を受け取れます。for i, v in enumerate(['tic', 'tac']) と書けば、i に 0、1 が、v に 'tic'、'tac' が順に入ります。range(len(s)) で添字を回して s[i] を引く書き方より簡潔です。zip() は 2 つ以上のシーケンスの要素を前から 1 つずつ組にする関数で、インデックスは付きません。range() は整数の並びを作るだけで、要素は取り出しません。reversed() はシーケンスを逆順にたどるための関数です。 出典 https://docs.python.org/ja/3/tutorial/datastructures.html#looping-⁠techniques

問14list(zip(['a', 'b', 'c'], [1, 2])) の結果として正しいものはどれですか。

正解は「[('a', 1), ('b', 2)]」です。zip() は渡したシーケンスの要素を前から 1 つずつ取り出してタプルの組にします。デフォルトでは、最も短いイテラブルが尽きた時点で止まり、長い方に残った要素は無視されます。2 つめのリストは 2 個で尽きるので、組は ('a', 1) と ('b', 2) の 2 つです。足りない側を None で埋めるのは zip() の動きではありません。長さがそろわなくてもデフォルトではエラーにならないので ValueError にもなりません。元のリストを 2 つ並べたリストにもならず、要素は必ずタプルの組にまとめられます。 出典 https://docs.python.org/ja/3/library/functions.html#zip

問15シーケンスを並べ替えた順でループするときに使う組み込み関数 sorted() の説明として正しいものはどれですか。

正解は「元のシーケンスを変えず、並べ替えた新しいリストを返す」です。sorted() は元のシーケンスを変更せず、並べ替えた新しいリストを返します。for f in sorted(basket) と書けば、basket の中身の並びはそのままで、ソートした順に要素をたどれます。タプルや文字列のような変更できないシーケンスにも使え、どれを渡しても結果はリストです。「並べ替えて None を返す」はリストの sort() メソッドの動きです。元のリスト自身を返す関数やメソッドはありません。結果はタプルではなくリストで、タプルを渡しても戻り値はリストになります。 出典 https://docs.python.org/ja/3/tutorial/datastructures.html#looping-⁠techniques

問16次のコードを実行したときの出力として正しいものはどれですか。
a = [1, 2, 2, 3]
for x in a:
    if x == 2:
        a.remove(x)
print(a)

正解は「[1, 2, 3]」です。for は位置 0、1、2 と順に要素を取り出します。位置 0 の 1 を見たあと、位置 1 の 2 で remove が動き、最初の 2 が消えて a は [1, 2, 3] に詰まります。次のループは位置 2 を見るので、詰まって位置 1 に来た 2 は飛ばされ、3 を見て終わります。結果は [1, 2, 3] です。「[1, 3]」は全ての 2 が消えると考えた誤りです。リストはループ中に変更してもエラーを出さないので RuntimeError にはなりません。remove は元のリストを変更するので、何も変わらないこともありません。ループ中に変えるのは間違いのもとで、チュートリアルは代わりに新しいリストを作る方が簡単で安全だとしています。 出典 https://docs.python.org/ja/3/tutorial/datastructures.html#looping-⁠techniques

問17次のコードを実行したときの出力として正しいものはどれですか。
x = 0 or [] or 'ok'
y = 'a' and '' and 'b'
print(x, repr(y))

正解は「ok ''」です。and と or は左から評価し、結果が決まった時点で止まる短絡演算子です。値をブール値ではなく一般の値として使うと、結果は最後に評価した引数そのものになります。x は 0 も [] も偽なので最後の 'ok' まで評価され、x は 'ok' です。y は 'a' が真なので次の '' を評価し、'' が偽なのでそこで止まり、y は '' です。「True False」は and や or がブール値を返すと考えた誤りです。「'b'」は and が偽の値で止まらないと考えた誤りです。「[]」は or が最初の値で止まると考えた誤りで、or は真の値が出るまで進みます。 出典 https://docs.python.org/ja/3/tutorial/datastructures.html#more-⁠on-⁠conditions

問18次のコードを実行したときの出力として正しいものはどれですか。
print((1, 2) < (1, 2, -1), [3] < [2, 9], 1 < 3 > 2)

正解は「True False True」です。シーケンスどうしは辞書式の順序で比べます。(1, 2) と (1, 2, -1) は先頭 2 つが等しく、短い方が長い方の先頭部分なので短い方が小さく True です。[3] と [2, 9] は先頭の 3 と 2 で決まり、3 の方が大きいので [3] < [2, 9] は False です。1 < 3 > 2 は比較の連鎖で 1 < 3 and 3 > 2 と同じ意味になり True です。1 つめを False とするのは、-1 が加わった方が小さいと考えた誤りです。2 つめを True とするのは、要素の数で比べると考えた誤りです。3 つめを False とするのは、1 < 3 の結果 True と 2 を比べると考えた誤りです。 出典 https://docs.python.org/ja/3/tutorial/datastructures.html#comparing-⁠sequences-⁠and-⁠other-⁠types

ほかの分野

Python 3 エンジニア認定基礎試験の頁に、6分野の入口と試験の案内があります。

続きはゆめさくで

試験の知識を仕事につなげる一歩を、ここにまとめています。