J'ai fait un script qui insère deux listes dans une autre tous les 4 éléments, mais cela prend beaucoup de temps à terminer. Voici mes deux très longues listes:

listOfX = ['567','765','456','457','546'....] len(383656)
listOfY = ['564','345','253','234','123'....] len(383656)

Et l'autre liste qui contient des données et où je veux ajouter les données des autres listes:

cleanData = ['2020-04-28T01:44:59.392043', 'c57', '0', '2020-04-28T01:44:59.392043', 'c57', '1'....] len(1145146)

Voici ce que je veux:

cleanData = ['2020-04-28T01:44:59.392043', 'c57', '0', 567, 564, '2020-04-28T01:44:59.392043', 'c57', '1', 765, 345]

Enfin, voici mon code:

  ## ADDING X AND Y TO ORIGINAL LIST
  addingValue = True
  valueItem = ""
  loopValue = 3
  xIndex = 0
  yIndex = 0
  print(len(listOfX))

  while addingValue:

    if xIndex > len(listOfX):
      break

    try:
      cleanData.insert(loopValue, listOfY[yIndex])
      cleanData.insert(loopValue, listOfX[xIndex])

    except IndexError:
      addingValue = False
      break

    xIndex += 1
    yIndex += 1
    loopValue += 5

Avez-vous une idée ? J'espère que c'est clair. Je vous remercie

0
Galileoomega 8 mai 2020 à 23:06

4 réponses

Meilleure réponse

Le principal problème avec votre solution était que, dans votre solution, vous avez inséré des éléments 2 * 383656 fois dans une liste existante. Chaque fois, tous les éléments situés après le point d'insertion devaient être décalés.

Il est donc plus rapide de créer une nouvelle liste.

Si pour une raison quelconque vous voulez que cleanData reste le même ancien objet avec les nouvelles données (peut-être, parce qu'une autre fonction / objet y fait référence et devrait voir les données modifiées) alors écrivez

cleanData[:] = blablabla 

Au lieu de

cleanData = blablabla

J'ai écrit deux solutions suivantes (la deuxième plus rapide seulement après que la réponse a été acceptée)

import functools
import operator
cleanData = functools.reduce(
    operator.iconcat,
    (list(v) for v in zip(*([iter(cleanData)] * 3), listOfX, listOfY)),
    [])

Et

import itertools
cleanData = list(itertools.chain.from_iterable(
    (v for v in zip(*([iter(cleanData)] * 3), listOfX, listOfY)),
    ))

Inconvénient potentiel de ma première solution (selon le contexte). L'utilisation de functools.reduce et operator.iconcat crée une liste et aucun générateur.

La deuxième solution renvoie une liste. Si vous voulez un générateur, supprimez simplement list( et un autre ) et ce sera un générateur

La deuxième solution est plus rapide que la première.

Ensuite, j'ai écrit du code pour comparer les performances et les résultats des deux solutions données et les miennes:

Pas une très grande différence (2,5x), mais la solution ci-dessus semble être un peu plus rapide que la première solution de @ Błotosmętek et aussi un peu plus rapide que la solution d'Alain T.

from contextlib import contextmanager
import functools
import itertools
import operator
import time

@contextmanager
def measuretime(comment):
    print("=" * 76)
    t0 = time.time()
    yield comment
    print("%s: %5.3fs" % (comment, time.time() - t0))
    print("-" * 76 + "\n")


N = 383656
t0 = time.time()
with measuretime("create listOfX"):
    listOfX = list(range(N))

with measuretime("create listOfY"):
    listOfY = list(range(1000000, 1000000 + N))

print("listOfX", len(listOfX), listOfX[:10])
print("listOfY", len(listOfY), listOfY[:10])

with measuretime("create cleanData"):
    origCleanData = functools.reduce(
        operator.iconcat,
        (["2020-010-1T01:00:00.%06d" % i, "c%d" % i, "%d" %i] for i in range(N)),
        [])

print("cleanData", len(origCleanData), origCleanData[:12])

cleanData = list(origCleanData)
with measuretime("funct.reduce operator icat + zip"):
    newcd1 = functools.reduce(
        operator.iconcat,
        (list(v) for v in zip(*([iter(cleanData)] * 3), listOfX, listOfY)),
        [])

print("NEW", len(newcd1), newcd1[:3*10])

cleanData = list(origCleanData)
with measuretime("itertools.chain + zip"):
    cleanData = list(itertools.chain.from_iterable(
        (v for v in zip(*([iter(cleanData)] * 3), listOfX, listOfY)),
        ))

print("NEW", len(cleanData), cleanData[:3*10])
assert newcd1 == cleanData

cleanData = list(origCleanData)
with measuretime("blotosmetek"):
    tmp = []
    n = min(len(listOfX), len(listOfY), len(cleanData)//3)
    for i in range(n):
       tmp.extend(cleanData[3*i : 3*i+3])
       tmp.append(listOfX[i])
       tmp.append(listOfY[i])
    cleanData = tmp

print("NEW", len(cleanData), cleanData[:3*10])
assert newcd1 == cleanData


cleanData = list(origCleanData)
with measuretime("alainT"):
    cleanData = [ v for i,x,y in zip(range(0,len(cleanData),3),listOfX,listOfY)
                for v in (*cleanData[i:i+3],x,y) ]

print("NEW", len(cleanData), cleanData[:3*10])
assert newcd1 == cleanData


La sortie sur mon ancien PC ressemble à:

============================================================================
create listOfX: 0.013s
----------------------------------------------------------------------------

============================================================================
create listOfY: 0.013s
----------------------------------------------------------------------------

listOfX 383656 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
listOfY 383656 [1000000, 1000001, 1000002, 1000003, 1000004, 1000005, 1000006, 1000007, 1000008, 1000009]
============================================================================
create cleanData: 0.454s
----------------------------------------------------------------------------

cleanData 1150968 ['2020-010-1T01:00:00.000000', 'c0', '0', '2020-010-1T01:00:00.000001', 'c1', '1', '2020-010-1T01:00:00.000002', 'c2', '2', '2020-010-1T01:00:00.000003', 'c3', '3']
============================================================================
funct.reduce operator icat + zip: 0.240s
----------------------------------------------------------------------------

NEW 1918280 ['2020-010-1T01:00:00.000000', 'c0', '0', 0, 1000000, '2020-010-1T01:00:00.000001', 'c1', '1', 1, 1000001, '2020-010-1T01:00:00.000002', 'c2', '2', 2, 1000002, '2020-010-1T01:00:00.000003', 'c3', '3', 3, 1000003, '2020-010-1T01:00:00.000004', 'c4', '4', 4, 1000004, '2020-010-1T01:00:00.000005', 'c5', '5', 5, 1000005]
============================================================================
itertools.chain + zip: 0.109s
----------------------------------------------------------------------------

NEW 1918280 ['2020-010-1T01:00:00.000000', 'c0', '0', 0, 1000000, '2020-010-1T01:00:00.000001', 'c1', '1', 1, 1000001, '2020-010-1T01:00:00.000002', 'c2', '2', 2, 1000002, '2020-010-1T01:00:00.000003', 'c3', '3', 3, 1000003, '2020-010-1T01:00:00.000004', 'c4', '4', 4, 1000004, '2020-010-1T01:00:00.000005', 'c5', '5', 5, 1000005]
============================================================================
blotosmetek: 0.370s
----------------------------------------------------------------------------

NEW 1918280 ['2020-010-1T01:00:00.000000', 'c0', '0', 0, 1000000, '2020-010-1T01:00:00.000001', 'c1', '1', 1, 1000001, '2020-010-1T01:00:00.000002', 'c2', '2', 2, 1000002, '2020-010-1T01:00:00.000003', 'c3', '3', 3, 1000003, '2020-010-1T01:00:00.000004', 'c4', '4', 4, 1000004, '2020-010-1T01:00:00.000005', 'c5', '5', 5, 1000005]
============================================================================
alainT: 0.258s
----------------------------------------------------------------------------

NEW 1918280 ['2020-010-1T01:00:00.000000', 'c0', '0', 0, 1000000, '2020-010-1T01:00:00.000001', 'c1', '1', 1, 1000001, '2020-010-1T01:00:00.000002', 'c2', '2', 2, 1000002, '2020-010-1T01:00:00.000003', 'c3', '3', 3, 1000003, '2020-010-1T01:00:00.000004', 'c4', '4', 4, 1000004, '2020-010-1T01:00:00.000005', 'c5', '5', 5, 1000005]

2
gelonida 8 mai 2020 à 22:26

En vous basant sur Blotometek avec un générateur, vous feriez quelque chose comme ceci:

def get_next_group():
    n = min(len(listOfX), len(listOfY), len(cleanData)//3)
    for i in range(n):
        tmp = cleanData[3*i : 3*i+3]
        tmp.append(listOfX[i])
        tmp.append(listOfY[i])

        yield tmp

#in you main code:

for x in get_next_group():
    #do something with x
    pass

L'avantage du code ci-dessus est que la combinaison n'est effectuée que pièce par pièce, à votre demande. Si vous faites quelque chose avec et ne le stockez pas dans une liste en mémoire, la surcharge de la mémoire est réduite. Puisque vous n'êtes plus lié à la mémoire, le processeur peut immédiatement traiter d'autres instructions sur chaque bloc au lieu d'attendre que tout soit combiné en premier.

0
shellster 8 mai 2020 à 20:44

Cela devrait être beaucoup plus rapide:

cleanData = [ v for i,x,y in zip(range(0,len(cleanData),3),listOfX,listOfY) 
                for v in (*cleanData[i:i+3],x,y) ]

Si vous utilisez des parenthèses au lieu de crochets, l'expression devient un générateur que vous pouvez utiliser pour parcourir les données fusionnées (par exemple avec une boucle for) sans réellement créer une copie dans une nouvelle liste

1
Alain T. 8 mai 2020 à 20:56

Voici la mise en œuvre de la suggestion de Shelister:

tmp = []
n = min(len(listOfX), len(listOfY), len(cleanData)//3)
for i in range(n):
   tmp.extend(cleanData[3*i : 3*i+3])
   tmp.append(listOfX[i])
   tmp.append(listOfY[i])
cleanData = tmp
2
Błotosmętek 8 mai 2020 à 20:36