Pythonで2次元配列を初期化する方法は?


262

私はpythonを始めており、2次元のリストを使用しようとしています。最初はすべての場所で同じ変数を入力します。私はこれを思いつきました:

def initialize_twodlist(foo):
    twod_list = []
    new = []
    for i in range (0, 10):
        for j in range (0, 10):
            new.append(foo)
        twod_list.append(new)
        new = []

望ましい結果が得られますが、回避策のように感じます。これを行うためのより簡単/より短い/よりエレガントな方法はありますか?


7
ほんの少し(または、誰が見ているかに応じて重要な)nitpick:リストは配列ではありません。配列が必要な場合は、numpyを使用します。
Arnab Datta 2012

この質問は似ています。Pythonでの多次元配列の初期化について説明します。
アンダーソングリーン

@ArnabDattaでは、どうやって多次元配列をnumpyで初期化しますか?
アンダーソングリーン


デフォルトのPythonでは、構造のような配列にデータを配置できますが、NumPy配列ほど効率的または有用ではありません。特に、大規模なデータセットを処理する場合。いくつかのドキュメントdocs.scipy.org/doc/numpy-1.10.1/user/basics.creation.html
jmdeamerは、

回答:


376

Pythonでよく登場するパターンは

bar = []
for item in some_iterable:
    bar.append(SOME EXPRESSION)

これは、リストの内包表記を導入する動機付けとなり、スニペットを

bar = [SOME EXPRESSION for item in some_iterable]

これは短く、時には明確です。通常は、これらを認識し、ループを内包表記に置き換えることがよくあります。

コードはこのパターンを2回実行します

twod_list = []                                       \                      
for i in range (0, 10):                               \
    new = []                  \ can be replaced        } this too
    for j in range (0, 10):    } with a list          /
        new.append(foo)       / comprehension        /
    twod_list.append(new)                           /

35
ちなみに、[[foo] * 10 for x in xrange(10)]を使用して、1つの内包を取り除くことができます。問題は、乗算が浅いコピーを行うことです。そのため、new = [foo] * 10 new = [new] * 10は、同じリストを10回含むリストを取得します。
Scott Wolchok

8
同様に、[foo] * 10正確に同じfoo10回のリストです。これは重要な場合とそうでない場合があります。
マイクグラハム、

2
最も単純なものを使用できます:wtod_list = [[x for xrange(10))] for x in xrange(10)]
indi60

2
魚がどのように見えるかを誰かに見せることは決して害にはなりません。
Csteele5 2016

2
およそマイク・グラハムさんのコメントのために[foo] * 10あなたが乱数(評価すると、配列を充填している場合、これは仕事ではないだろうと、この意味:[random.randint(1,2)] * 10[1] * 10[2] * 10。あなたがすべて1または2秒の列の代わりに、ランダムな配列を取得することを意味
シーズーリー

224

リスト内包表記を使用できます。

x = [[foo for i in range(10)] for j in range(10)]
# x is now a 10x10 array of 'foo' (which can depend on i and j if you want)

1
サイズ(10)は同じなので、ネストされたループは最初に来る必要があります[範囲内のfoo(jは範囲(range_of_j)] for iは範囲(range_of_i)]
Dineshkumar

2
この答えはうまくいきますが、私iは行と列を繰り返し処理するので、範囲を2つの異なる数値に理解し、変更するために、構文でj入れ替えることijお勧めします。
DragonKnight

138

この方法は、ネストされたリストの内包より高速です

[x[:] for x in [[foo] * 10] * 10]    # for immutable foo!

小規模および大規模なリストの場合のpython3のタイミングをいくつか示します

$python3 -m timeit '[x[:] for x in [[1] * 10] * 10]'
1000000 loops, best of 3: 1.55 usec per loop

$ python3 -m timeit '[[1 for i in range(10)] for j in range(10)]'
100000 loops, best of 3: 6.44 usec per loop

$ python3 -m timeit '[x[:] for x in [[1] * 1000] * 1000]'
100 loops, best of 3: 5.5 msec per loop

$ python3 -m timeit '[[1 for i in range(1000)] for j in range(1000)]'
10 loops, best of 3: 27 msec per loop

説明:

[[foo]*10]*10同じオブジェクトのリストを10回繰り返して作成します。1つの要素を変更すると各行の同じ要素が変更されるため、これを使用することはできません。

x[:]と同等ですlist(X)が、名前の検索を回避するため、少し効率的です。どちらの方法でも、各行の浅いコピーが作成されるため、すべての要素が独立しています。

fooただし、すべての要素は同じオブジェクトであるため、foomutableの場合、このスキームは使用できません。使用する必要があります。

import copy
[[copy.deepcopy(foo) for x in range(10)] for y in range(10)]

またはs Fooを返すクラス(または関数)を想定foo

[[Foo() for x in range(10)] for y in range(10)]

4
@マイク、太字の部分を見逃しましたか?fooが変更可能である場合、他のどの回答も機能しません(fooをまったく変更しない場合を除く)
John La Rooy

1
を使用して任意のオブジェクトを正しくコピーすることはできませんcopy.deepcopy。任意の可変オブジェクトがある場合は、データに固有の計画が必要です。
マイクグラハム

1
ループで
それほど

1
@JohnLaRooy交換したxと思いますy。あるべきではない[[copy.deepcopy(foo) for y in range(10)] for x in range(10)]
user3085931

1
@Nilsは、[foo]*1010種類のオブジェクトを作成しません-しかし、のようにそれは、fooが不変である場合の違いを見落とすことは簡単ですintstr
John La Rooy、2018年

137

使用しないでください[[v]*n]*n。トラップです。

>>> a = [[0]*3]*3
>>> a
[[0, 0, 0], [0, 0, 0], [0, 0, 0]]
>>> a[0][0]=1
>>> a
[[1, 0, 0], [1, 0, 0], [1, 0, 0]]

だが

    t = [ [0]*3 for i in range(3)]

よく働く。


26
はい、私もこの罠に陥りました。オブジェクト(リスト)のを*コピーしているためですaddress
chinuy 2017

1
これは私を手に入れたので、賛成票を投じました。、明確であるために[[0] * col for _ in range(row)]
Abhijit Sarkar

62

Pythonで2次元配列を初期化するには:

a = [[0 for x in range(columns)] for y in range(rows)]

4
すべての値を0に初期化するには、単にを使用しますa = [[0 for x in range(columns)] for y in range(rows)]
ZX9

28
[[foo for x in xrange(10)] for y in xrange(10)]

1
xrange()はpython3.5で削除されました
MiaeKim

これが機能しない理由:[0 * col] *行。一部の要素を変更すると、他の場所で複製されます。しかし、なぜかわかりませんか?
コードmuncher

それは問題のコードとまったく同じことをするからです。
Ignacio Vazquez-Abrams

2
@codemuncher [[0] * col] * row2Dリストをそのように初期化すると、Pythonが各行の個別のコピーを作成しないため、希望どおりの結果が得られません。代わりに、の同じコピーへのポインタで外部リストを初期化します[0]*col。行の1つに対して行った編集はすべて、実際にはメモリ内の同じデータを指しているため、残りの行に反映されます。
Addie

考えただけですが、これらのリストすべてを追加するのに適していませんか?すなわち。次元3 * 6の空の2Dリストが必要で、index [0] [0]、[1] [0]、[2] [0]などに追加して、18要素すべてを埋めたい場合、これらの答えは正しく機能しますか?
mLstudent33

22

通常、多次元配列が必要な場合は、リストのリストではなく、派手な配列またはおそらく辞書が必要です。

たとえば、numpyでは次のようにします

import numpy
a = numpy.empty((10, 10))
a.fill(foo)

2
numpy素晴らしいですが、私はそれが初心者のためのやり過ぎのビットかもしれないと思います。
EstebanKüber10年

3
numpyは多次元配列型を提供します。リストから適切な多次元配列を構築することは可能ですが、初心者にとっては、numpyを使用するよりも有用で難しく困難です。ネストされたリストは、一部のアプリケーションには最適ですが、通常、2次元配列を必要とするユーザーにとって最適なものではありません。
マイクグラハム

1
数年にわたって深刻なpythonアプリをときどきやってきた数年後、標準のpython配列の癖が先に進むことを正当化するようですnumpy。+1
javadba 2017

12

あなたはこれを行うことができます:

[[element] * numcols] * numrows

例えば:

>>> [['a'] *3] * 2
[['a', 'a', 'a'], ['a', 'a', 'a']]

しかし、これには望ましくない副作用があります。

>>> b = [['a']*3]*3
>>> b
[['a', 'a', 'a'], ['a', 'a', 'a'], ['a', 'a', 'a']]
>>> b[1][1]
'a'
>>> b[1][1] = 'b'
>>> b
[['a', 'b', 'a'], ['a', 'b', 'a'], ['a', 'b', 'a']]

11
私の経験では、この「望ましくない」影響は、いくつかの非常に悪い論理エラーの原因になることがよくあります。私の意見では、このアプローチは避けるべきです。代わりに、@ Vipulの答えの方がはるかに優れています。
アランチューリング

このアプローチはうまくいきますが、なぜコメントでそれが悪いと言う人がいますか?
Bravo

1
副作用が少ないため、実際にはマトリックスとして扱うことはできません。内容を変更する必要がない場合は問題ありません。
hithwen 2017年


8

それがまばらに配置された配列である場合、タプルでキー付けされたディクショナリを使用したほうがよい場合があります。

dict = {}
key = (a,b)
dict[key] = value
...

5
t = [ [0]*10 for i in [0]*10]

要素ごとに新しいもの[0]*10が作成されます。


4

不適切なアプローチ:[[なし* m]​​ * n]

>>> m, n = map(int, raw_input().split())
5 5
>>> x[0][0] = 34
>>> x
[[34, None, None, None, None], [34, None, None, None, None], [34, None, None, None, None], [34, None, None, None, None], [34, None, None, None, None]]
>>> id(x[0][0])
140416461589776
>>> id(x[3][0])
140416461589776

このアプローチでは、Pythonは外側の列に異なるアドレス空間を作成することを許可しないため、予想よりもさまざまな誤動作が発生します。

正しいアプローチですが、例外があります:

y = [[0 for i in range(m)] for j in range(n)]
>>> id(y[0][0]) == id(y[1][0])
False

これは良い方法ですが、デフォルト値を次のように設定すると例外があります None

>>> r = [[None for i in range(5)] for j in range(5)]
>>> r
[[None, None, None, None, None], [None, None, None, None, None], [None, None, None, None, None], [None, None, None, None, None], [None, None, None, None, None]]
>>> id(r[0][0]) == id(r[2][0])
True

したがって、このアプローチを使用してデフォルト値を適切に設定してください。

絶対正しい:

マイクのダブルループの返信に従ってください。


3
Matrix={}
for i in range(0,3):
  for j in range(0,3):
    Matrix[i,j] = raw_input("Enter the matrix:")

1
このコードは質問に答えることがありますが、このコードが質問に答える理由や方法に関する追加のコンテキストを提供すると、長期的な価値が向上します。
Ajean 2016年


3

これを作成するには、最も単純な考え方を使用してください。

wtod_list = []

サイズを追加します。

wtod_list = [[0 for x in xrange(10)] for x in xrange(10)]

または、最初にサイズを宣言したい場合。使用するのは:

   wtod_list = [[0 for x in xrange(10)] for x in xrange(10)]

1

@Arnabと@Mikeが指摘したように、配列はリストではありません。いくつかの違いは次のとおりです。1)配列は初期化中にサイズが固定されます。2)配列は通常、リストよりも少ない操作をサポートします。

ほとんどの場合、やり過ぎかもしれませんが、python ctypes(c libraries)を使用してハードウェア配列の実装を活用する基本的な2D配列の実装を次に示します

import ctypes
class Array:
    def __init__(self,size,foo): #foo is the initial value
        self._size = size
        ArrayType = ctypes.py_object * size
        self._array = ArrayType()
        for i in range(size):
            self._array[i] = foo
    def __getitem__(self,index):
        return self._array[index]
    def __setitem__(self,index,value):
        self._array[index] = value
    def __len__(self):
        return self._size

class TwoDArray:
    def __init__(self,columns,rows,foo):
        self._2dArray = Array(rows,foo)
        for i in range(rows):
            self._2dArray[i] = Array(columns,foo)

    def numRows(self):
        return len(self._2dArray)
    def numCols(self):
        return len((self._2dArray)[0])
    def __getitem__(self,indexTuple):
        row = indexTuple[0]
        col = indexTuple[1]
        assert row >= 0 and row < self.numRows() \
               and col >=0 and col < self.numCols(),\
               "Array script out of range"
        return ((self._2dArray)[row])[col]

if(__name__ == "__main__"):
    twodArray = TwoDArray(4,5,5)#sample input
    print(twodArray[2,3])

1

私が理解した重要なことは次のとおりです。配列を(任意の次元で)初期化するとき、配列のすべての位置にデフォルト値を指定する必要があります。その後、初期化のみが完了します。その後、配列の任意の位置で新しい値を変更または受信できます。以下のコードは私にとって完全に機能しました

N=7
F=2

#INITIALIZATION of 7 x 2 array with deafult value as 0
ar=[[0]*F for x in range(N)]

#RECEIVING NEW VALUES TO THE INITIALIZED ARRAY
for i in range(N):
    for j in range(F):
        ar[i][j]=int(input())
print(ar)

1

numpyを使用すると、2D配列を簡単に作成できます。

import numpy as np

row = 3
col = 5
num = 10
x = np.full((row, col), num)

バツ

array([[10, 10, 10, 10, 10],
       [10, 10, 10, 10, 10],
       [10, 10, 10, 10, 10]])

1
row=5
col=5
[[x]*col for x in [b for b in range(row)]]

上記は5x5 2D配列を提供します

[[0, 0, 0, 0, 0],
 [1, 1, 1, 1, 1],
 [2, 2, 2, 2, 2],
 [3, 3, 3, 3, 3],
 [4, 4, 4, 4, 4]]

ネストされたリスト内包表記を使用しています。以下のような内訳:

[[x]*col for x in [b for b in range(row)]]

[x] * col->
xで評価される最終式-> xは、イテレーターによって提供される値になります
[b for b(範囲)(行)]]->イテレーター。

[範囲(行)のbのb]]行= 5
なので、これは[0,1,2,3,4]と評価されるため、次のように簡略化されます。

[[x]*col for x in [0,1,2,3,4]]

これは、[[0,1,2,3,4]]のxについて[[0] * 5]と評価されます-> x = 0を使用して1回目の反復
[[1、*、2、 3,4]]-> x = 1を使用して2回目の反復
[[2] * 5 in x in [0,1,2,3,4]]-> x = 2を使用して3回目の反復
[[3] * 5 x for [0,1,2,3,4]]-> with x = 3 4回目の反復
[[4] * 5 for x in [0,1,2,3,4]]-> with x = 4 5回目の反復


0

これは、追加のライブラリを使用せずに、新しいプログラマを教えるために私が見つけた最高のものです。でももっと良いものが欲しいです。

def initialize_twodlist(value):
    list=[]
    for row in range(10):
        list.append([value]*10)
    return list

0

ここに簡単な方法があります:

import numpy as np
twoD = np.array([[]*m]*n)

すべてのセルを「x」値で初期化するには、以下を使用します。

twoD = np.array([[x]*m]*n

0

2次元配列の初期化にこのアプローチをよく使用します

n=[[int(x) for x in input().split()] for i in range(int(input())]


0

寸法を追加するための一般的なパターンは、このシリーズから描くことができます:

x = 0
mat1 = []
for i in range(3):
    mat1.append(x)
    x+=1
print(mat1)


x=0
mat2 = []
for i in range(3):
    tmp = []
    for j in range(4):
        tmp.append(x)
        x+=1
    mat2.append(tmp)

print(mat2)


x=0
mat3 = []
for i in range(3):
    tmp = []
    for j in range(4):
        tmp2 = []
        for k in range(5):
            tmp2.append(x)
            x+=1
        tmp.append(tmp2)
    mat3.append(tmp)

print(mat3)

SOへようこそ。この質問にはすでに大々的に受け入れられた回答があります。一見すると、この投稿は実際には質問に答えていません。ガイダンスについては、stackoverflow.com / help / how-to-answerをご覧ください。
Nick

0

これ[[0] * 10] * 10を試すことができます。これは、各セルの値が0の10行と10列の2D配列を返します。


これは基本的に、stackoverflow.com
a / 25601284/2413201

2
これにより、同じ行への10個のポインタの配列が作成されます。その場合はa = [[0]*10]*10、その後a[0][0] = 1、あなたは各行の最初の要素は今1に等しいことがわかります
andnik

0

lst = [[0] * m for i for range(n)]

すべての行列n =行とm =列を初期化します


コードをコードとしてフォーマットできますか?より読みやすくなります。
トーマス

0

別の方法は、辞書を使用して2次元配列を保持することです。

twoD = {}
twoD[0,0] = 0
print(twoD[0,0]) # ===> prints 0

これは、任意の1D、2D値を保持でき、これを0他のint値に初期化するには、コレクションを使用します

import collections
twoD = collections.defaultdict(int)
print(twoD[0,0]) # ==> prints 0
twoD[1,1] = 1
print(twoD[1,1]) # ==> prints 1

0

コード:

num_rows, num_cols = 4, 2
initial_val = 0
matrix = [[initial_val] * num_cols for _ in range(num_rows)]
print(matrix) 
# [[0, 0], [0, 0], [0, 0], [0, 0]]

initial_val 不変でなければなりません。


-3
from random import randint
l = []

for i in range(10):
    k=[]
    for j in range(10):
        a= randint(1,100)
        k.append(a)

    l.append(k)




print(l)
print(max(l[2]))

b = []
for i in range(10):
    a = l[i][5]
    b.append(a)

print(min(b))

4
コードの内容を説明するテキストを追加してください。
whackamadoodle3000

1
通常は、匿名のコードのいくつかの行を投稿するだけでなく、解決策を説明する方が良いでしょう。どのようにすればよい答えを書くことができ、また完全にコードベースの答えを説明することもできます
Massimiliano Kraus 2017年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.