Lista Python vs. Matriz - quando usar?

375

Se você estiver criando uma matriz 1d, poderá implementá-la como uma lista ou usar o módulo 'matriz' na biblioteca padrão. Eu sempre usei Listas para matrizes 1d.

Qual é a razão ou circunstância em que eu gostaria de usar o módulo array?

É para otimização de desempenho e memória, ou estou perdendo algo óbvio?

Corey Goldberg
fonte

Respostas:

438

Basicamente, as listas Python são muito flexíveis e podem conter dados arbitrários completamente heterogêneos e podem ser anexados com muita eficiência, em tempo constante e amortizado . Se você precisar diminuir e aumentar sua lista com eficiência e sem problemas, eles são o caminho a percorrer. Mas eles usam um espaço muito mais do que matrizes C .

O array.arraytipo, por outro lado, é apenas um invólucro fino em matrizes C. Ele pode conter apenas dados homogêneos, todos do mesmo tipo e, portanto, usa apenas sizeof(one object) * lengthbytes de memória. Principalmente, você deve usá-lo quando precisar expor uma matriz C a um ramal ou a uma chamada do sistema (por exemplo, ioctlou fctnl).

array.arraytambém é uma maneira razoável de representar uma sequência mutável no Python 2.x ( array('B', bytes)). No entanto, o Python 2.6+ e 3.x oferece uma sequência de bytes mutável como bytearray.

No entanto, se você deseja fazer contas em uma matriz homogênea de dados numéricos, é muito melhor usar o NumPy, que pode vetorizar automaticamente as operações em matrizes multidimensionais complexas.

Para resumir uma longa história : array.arrayé útil quando você precisa de uma matriz C homogênea de dados por outros motivos que não sejam matemática .

Dan Lenski
fonte
9
Numpy.ndarray tem o mesmo espaço de memória que array.array?
Gordon Bean
6
@Gordon, deve ser muito semelhante no caso de uma matriz grande e contígua: ambos exigirão sizeof(element)× (número de elementos) bytes, além de um pequeno cabeçalho fixo para sobrecarga. No entanto, o ndarray tem algumas opções avançadas para lidar com matrizes descontínuas e esparsas, e acho que algumas estratégias conectáveis ​​para alocar memória para matrizes grandes ... alguns desses recursos avançados tornarão o usuário menos memória, enquanto outros melhorarão o desempenho usando mais memória.
quer
Também é útil quando a memória é um problema, como quando a programação microcontroladores com micropython
janscas
Pode-se procurar o i-ésimo elemento de uma matriz em um tempo constante, enquanto que na lista vinculada, ela leva ordem 'n' no pior caso. Qual é o tempo de pesquisa do i'th elemento em uma lista python?
Nithish Inpursuit Ofhappiness
7
@NithishInpursuitOfhappiness, uma lista Python não é uma lista vinculada. Ele é representado internamente como uma matriz e possui as mesmas características de complexidade de tempo que o ArrayList do Java. Assim, obter e definir o i-ésimo elemento de uma lista Python leva tempo constante . A adição de um elemento a uma lista Python leva um tempo constante amortizado, pois o tamanho da matriz é dobrado quando o espaço acaba. Inserir ou remover um elemento do meio de uma lista Python leva O (n) tempo porque os elementos precisam ser alterados. Para referência, consulte: wiki.python.org/moin/TimeComplexity
geofflee
66

Para quase todos os casos, a lista normal é a escolha certa. O módulo de matrizes é mais como um invólucro fino sobre matrizes C, que fornece tipos de contêineres fortemente tipados (consulte a documentação ), com acesso a tipos mais parecidos com C, como assinados / não assinados, curtos ou duplos, que não fazem parte do tipos. Eu diria que use o módulo matrizes apenas se você realmente precisar, em todos os outros casos, fique com as listas.

André
fonte
3
Possível, nunca o usei realmente, mas seria interessante executar alguns micro benchmarks.
André
13
Na verdade, fiz um teste rápido - cronometrei a soma de uma lista com entradas de 100 milhões e o mesmo teste com a matriz correspondente, e a lista era na verdade 10% mais rápida.
Moe
38
As listas são mais rápidas, porque as operações nos dados "brutos" da matriz precisam criar e destruir continuamente objetos python ao ler ou gravar na matriz.
tzot 6/10/08
7
@Moe, como indiquei na minha resposta anterior, de Python built-in arrayé não significava para fazer matemática . Se você tentar o NumPy ndarraypara somar uma matriz de 10 ^ 8 números, ele desaparecerá completamente list. O @tzot tem a ideia certa de por que o built-in arrayé lento para a matemática.
precisa saber é o seguinte
2
Acabei de testar, o numpy é 86,6x mais rápido na minha máquina.
Mark
53

O módulo array é uma daquelas coisas que você provavelmente não precisa se não souber por que o usaria (e observe que não estou tentando dizer isso de maneira condescendente!) . Na maioria das vezes, o módulo array é usado para fazer interface com o código C. Para fornecer uma resposta mais direta à sua pergunta sobre desempenho:

As matrizes são mais eficientes que as listas para alguns usos. Se você precisar alocar uma matriz que você SAIBA que não será alterada, as matrizes poderão ser mais rápidas e usar menos memória. O GvR tem uma anedota de otimização na qual o módulo do array acaba sendo o vencedor (leitura longa, mas vale a pena).

Por outro lado, parte do motivo pelo qual as listas consomem mais memória do que matrizes é porque o python alocará alguns elementos extras quando todos os elementos alocados forem usados. Isso significa que anexar itens às listas é mais rápido. Portanto, se você planeja adicionar itens, uma lista é o caminho a percorrer.

TL; DR Eu usaria apenas uma matriz se você tivesse uma necessidade excepcional de otimização ou precisas interagir com o código C (e não puder usar o pyrex ).

Jason Baker
fonte
11
+1 para um exemplo concreto e mencionando o benefício da velocidade. A resposta principal me fez pensar: "Existe uma troca de memória do tempo?" e "Existe alguma utilidade para isso que não seja um caso de pouca memória esotérica?"
leewz
@leewz exatamente, isso deve ser considerado como resposta.
Gauri Shankar Badola
21

É uma troca!

profissionais de cada um:

Lista

  • flexível
  • pode ser heterogêneo

matriz (ex: matriz numpy)

  • matriz de valores uniformes
  • homogêneo
  • compacto (em tamanho)
  • eficiente (funcionalidade e velocidade)
  • conveniente
Mohammad Mahdi KouchakYazdi
fonte
2
a questão está se referindo ao módulo array em python; matrizes não numpy. Eles não têm muitos profissionais, exceto a eficiência do tamanho. Eles não são mais rápidos.
NONONONONO 11/07/19
14

Meu entendimento é que as matrizes são armazenadas com mais eficiência (ou seja, como blocos contíguos de memória vs. ponteiros para objetos Python), mas não tenho conhecimento de nenhum benefício no desempenho. Além disso, com matrizes você deve armazenar primitivas do mesmo tipo, enquanto listas podem armazenar qualquer coisa.

Ben Hoffstein
fonte
8

As matrizes da biblioteca padrão são úteis para E / S binária, como converter uma lista de ints em uma string para gravar em, por exemplo, um arquivo wave. Dito isto, como muitos já observaram, se você for fazer algum trabalho real, considere usar o NumPy.

giltay
fonte
6

Se você estiver usando matrizes, considere os pacotes numpy ou scipy, que oferecem matrizes com muito mais flexibilidade.

Alex Coventry
fonte
5

A matriz pode ser usada apenas para tipos específicos, enquanto as listas podem ser usadas para qualquer objeto.

Matrizes também podem apenas dados de um tipo, enquanto uma lista pode ter entradas de vários tipos de objetos.

Matrizes também são mais eficientes para alguns cálculos numéricos.

Hortitude
fonte
4
As matrizes python incorporadas não são eficientes em termos de desempenho, apenas em memória.
tzot 6/10/08
Existem casos em que matrizes são mais eficientes em termos de processamento. Veja meu post abaixo: stackoverflow.com/questions/176011/…
Jason Baker
0

Uma diferença importante entre a matriz numpy e a lista é que as fatias da matriz são visualizações na matriz original. Isso significa que os dados não são copiados e quaisquer modificações na exibição serão refletidas na matriz de origem.

vivek
fonte
0

Esta resposta resumirá quase todas as perguntas sobre quando usar List e Array:

  1. A principal diferença entre esses dois tipos de dados é a operação que você pode executar neles. Por exemplo, você pode dividir uma matriz por 3 e cada elemento da matriz será dividido por 3. O mesmo não pode ser feito com a lista.

  2. A lista é parte da sintaxe do python, portanto não precisa ser declarada, enquanto você deve declarar a matriz antes de usá-la.

  3. Você pode armazenar valores de diferentes tipos de dados em uma lista (heterogênea), enquanto na Matriz você pode armazenar apenas valores do mesmo tipo de dados (homogêneo).

  4. As matrizes são ricas em funcionalidades e rápidas, e são amplamente usadas para operações aritméticas e para armazenar uma grande quantidade de dados - em comparação com a lista.

  5. Matrizes consomem menos memória em comparação com listas.

Dipen Gajjar
fonte
0

Com relação ao desempenho, veja alguns números comparando listas, matrizes e matrizes python (todas com Python 3.7 em um Macbook Pro de 2017). O resultado final é que a lista python é mais rápida para essas operações.

# Python list with append()
np.mean(timeit.repeat(setup="a = []", stmt="a.append(1.0)", number=1000, repeat=5000)) * 1000
# 0.054 +/- 0.025 msec

# Python array with append()
np.mean(timeit.repeat(setup="import array; a = array.array('f')", stmt="a.append(1.0)", number=1000, repeat=5000)) * 1000
# 0.104 +/- 0.025 msec

# Numpy array with append()
np.mean(timeit.repeat(setup="import numpy as np; a = np.array([])", stmt="np.append(a, [1.0])", number=1000, repeat=5000)) * 1000
# 5.183 +/- 0.950 msec

# Python list using +=
np.mean(timeit.repeat(setup="a = []", stmt="a += [1.0]", number=1000, repeat=5000)) * 1000
# 0.062 +/- 0.021 msec

# Python array using += 
np.mean(timeit.repeat(setup="import array; a = array.array('f')", stmt="a += array.array('f', [1.0]) ", number=1000, repeat=5000)) * 1000
# 0.289 +/- 0.043 msec

# Python list using extend()
np.mean(timeit.repeat(setup="a = []", stmt="a.extend([1.0])", number=1000, repeat=5000)) * 1000
# 0.083 +/- 0.020 msec

# Python array using extend()
np.mean(timeit.repeat(setup="import array; a = array.array('f')", stmt="a.extend([1.0]) ", number=1000, repeat=5000)) * 1000
# 0.169 +/- 0.034
Hefesto
fonte