Je suis désolé pour le long message. S'il vous plaît, quelqu'un pourrait-il m'aider à fusionner deux listes imbriquées de longueurs différentes? Il existe d'innombrables exemples de rejoindre des listes "élément par élément" sur Google et SO, mais aucun ne semble couvrir exactement mon cas. Je dois le faire des milliers de fois, sur des listes qui font environ 1 million de lignes chacune.

Une liste a le format:

shortdata = [
["2015.01.01 22:00:00","1.21036","1.21032","1.21033","1.21038"],
["2015.01.01 22:00:02","1.21034","1.21039","1.21038","1.21037"],
["2015.01.01 22:00:04","1.21032","1.21035","1.21034","1.21034"],
["2015.01.01 22:00:06","1.21021","1.21027","1.21028","1.21028"],
...
["2015.01.01 22:00:56","1.21040","1.21038","1.21039","1.21039"],
["2015.01.01 22:00:58","1.21041","1.21042","1.21047","1.21050"],
["2015.01.01 22:01:00","1.21044","1.21032","1.21033","1.21035"],
["2015.01.01 22:01:02","1.21047","1.21033","1.21035","1.21035"],
["2015.01.01 22:01:04","1.21045","1.21034","1.21036","1.21032"],
...
]

L'autre liste a le format:

longdata = [
["2015.01.01 22:00:00","1.21036","1.21032","1.21033","1.21038"],
["2015.01.01 22:01:00","1.21044","1.21032","1.21033","1.21035"],
...
]

Je voudrais joindre les sous-listes afin que la sortie soit une liste des sous-listes combinées, éventuellement avec un remplissage des colonnes vides, c'est-à-dire quelque chose comme:

combineddata = [
["2015.01.01 22:00:00","1.21036","1.21032","1.21033","1.21038", "", "", "2015.01.01 22:00:00","1.21036","1.21032","1.21033","1.21038"],
["2015.01.01 22:00:00","1.21036","1.21032","1.21033","1.21038", "", "", "2015.01.01 22:00:02","1.21034","1.21039","1.21038","1.21037"],
["2015.01.01 22:00:00","1.21036","1.21032","1.21033","1.21038", "", "", "2015.01.01 22:00:04","1.21032","1.21035","1.21034","1.21034"],
["2015.01.01 22:00:00","1.21036","1.21032","1.21033","1.21038", "", "", "2015.01.01 22:00:06","1.21021","1.21027","1.21028","1.21028"],
...
["2015.01.01 22:00:00","1.21036","1.21032","1.21033","1.21038", "", "", "2015.01.01 22:00:56","1.21040","1.21038","1.21039","1.21039"],
["2015.01.01 22:00:00","1.21036","1.21032","1.21033","1.21038", "", "",["2015.01.01 22:00:58","1.21041","1.21042","1.21047","1.21050"],
["2015.01.01 22:01:00","1.21044","1.21032","1.21033","1.21035", "","", "2015.01.01 22:01:00","1.21044","1.21032","1.21033","1.21035"],
["2015.01.01 22:01:00","1.21044","1.21032","1.21033","1.21035", "", "", "2015.01.01 22:01:02","1.21047","1.21033","1.21035","1.21035"],
["2015.01.01 22:01:00","1.21044","1.21032","1.21033","1.21035", "", "", "2015.01.01 22:01:04","1.21045","1.21034","1.21036","1.21032"],
...
]

Les «données minute» sont répétées sur chaque ligne délibérément car elles sont nécessaires pour les calculs ligne par ligne.

Si je fais une simple compréhension de liste, cela ne fonctionne pas parce que les listes sont de longueurs différentes - il y a évidemment beaucoup plus de données 2 secondes que de données 1 minute.

J'ai alors pensé que je pouvais dupliquer les éléments des données d'une minute pour lui donner la même longueur que les données des 2 afin de pouvoir ensuite compresser les deux listes. Cela a également échoué de façon spectaculaire:

expandedlist = [[x] * n for x in longdata]

Mais je me retrouve avec un format incorrect, par exemple pour n = 3 pour la démonstration (plutôt que 30!):

[[['2015.01.01 22:00:00', '1.21038', '1.21038', '1.21038', '1.21038'], ['2015.01.01 22:00:00', '1.21038', '1.21038', '1.21038', '1.21038'], ['2015.01.01 22:00:00', '1.21038', '1.21038', '1.21038', '1.21038']], [['2015.01.01 22:01:00', '1.21037', '1.21037', '1.21037', '1.21037'], ['2015.01.01 22:01:00', '1.21037', '1.21037', '1.21037', '1.21037'], ['2015.01.01 22:01:00', '1.21037', '1.21037', '1.21037', '1.21037']], 
...

Il y a donc un peu trop d'imbrication. J'ai essayé de supprimer les signes extérieurs «[]», en essayant list (x) au lieu de [x], et en utilisant des crochets externes «(», dont aucun ne donne quelque chose qui est dans le format prévu pour être compressé avec les données 2s.

J'ai pensé que je pourrais peut-être utiliser itertools.izip_longest () avec une valeur de remplissage et lui faire «remplir» les lignes 2s avec les données d'une minute requises, quelque chose comme:

combinedlist = list(itertools.izip_longest(longdata, shortdata, fillvalue=<something goes here>))
print combinedlist

Je ne comprends pas vraiment la syntaxe et même remplir la valeur de fichier avec une simple chaîne montre qu'elle ne ressemble pas beaucoup à la sortie prévue. Je reçois:

[(['2015.01.01 22:00:00', '1.21038', '1.21038', '1.21038', '1.21038'], ['2015.01.01 22:00:00', '1.21038', '1.21038', '1.21038', '1.21038']), (['2015.01.01 22:01:00', '1.21037', '1.21037', '1.21037', '1.21037'], ['2015.01.01 22:00:02', '1.21038', '1.21038', '1.21038', '1.21038']), (['2015.01.01 22:02:00', '1.2105', '1.2105', '1.2105', '1.2105'], ['2015.01.01 22:00:04', '1.21038', '1.21038', '1.21038', '1.21038']), (['2015.01.01 22:03:00', '1.21043', '1.21043', '1.21043', '1.21043'], ['2015.01.01 22:00:06', '1.21038', '1.21038', '1.21038', '1.21038']), (['2015.01.01 22:04:00', '1.21049', '1.21049', '1.21049', '1.21049'], ['2015.01.01 22:00:08', '1.21038', '1.21038', '1.21038', '1.21038']), (['2015.01.01 22:05:00', '1.21043', '1.21043', '1.21038', '1.21038'], ['2015.01.01 22:00:10', '1.21038', '1.21038', '1.21038', '1.21038']), (['2015.01.01 22:06:00', '1.21037', '1.21037', '1.21037', '1.21037'], ['2015.01.01 22:00:12', '1.21038', '1.21038', '1.21038', '1.21038']), (['2015.01.01 22:07:00', '1.21041', '1.21041', '1.21041', '1.21041'], ['2015.01.01 22:00:14', '1.21038', '1.21038', '1.21038', '1.21038']), (['2015.01.01 22:08:00', '1.21037', '1.21037', '1.21037', '1.21037'], ['2015.01.01 22:00:16', '1.21038', '1.21038', '1.21038', '1.21038']), ('foo', ['2015.01.01 22:00:18', '1.21038', '1.21038', '1.21038', '1.21038']), ('foo', ['2015.01.01 22:00:20', '1.21038', '1.21038', '1.21038', '1.21038']), ('foo',...

Enfin, j'ai pensé que je pouvais mettre toutes les données d'une minute dans un dictionnaire, puis rechercher les 17 caractères les plus à gauche de l'horodatage 2s (par exemple "2015.01.01 22:00:") dans le dictionnaire pour faire la jointure, mais cela semble un peu lourd (?).

J'ai également envisagé une méthode de bissection (c.-à-d. Pour bissecter les données minute chaque fois que j'atteins un ": 00" dans les horodatages de données 2s, mais je ne suis pas sûr que ce sera le moyen le plus rapide non plus.

Quelle serait la façon la plus rapide (ou la plus élégante) de faire ce que j'essaye de faire, ou dois-je écrire une boucle complète pour joindre les listes?

Toute aide serait très appréciée!

Sincères amitiés,

Paul

1
Paul 17 avril 2018 à 16:55

3 réponses

Meilleure réponse

Je garderais une position dans les données des minutes (en commençant par 0) tout en parcourant les secondes données. Chaque fois que je vois un incrément d'une minute dans les secondes données, j'augmente cette position dans les données des minutes. Ensuite, je voudrais yield les éléments comme souhaité:

shortdata = [
  ["2015.01.01 22:00:00","1.21036","1.21032","1.21033","1.21038"],
  ["2015.01.01 22:00:02","1.21034","1.21039","1.21038","1.21037"],
  # ...
  ["2015.01.01 22:00:58","1.21041","1.21042","1.21047","1.21050"],
  ["2015.01.01 22:01:00","1.21044","1.21032","1.21033","1.21035"],
  ["2015.01.01 22:01:02","1.21047","1.21033","1.21035","1.21035"],
  # ...
]

longdata = [
  ["2015.01.01 22:00:00","1.21036","1.21032","1.21033","1.21038"],
  ["2015.01.01 22:01:00","1.21044","1.21032","1.21033","1.21035"],
  # ...
]

def each_mixed_line(sh, lo):
  lo_pos = 0
  for sh_line in sh:
    while lo_pos < len(lo)-1 and lo[lo_pos+1][0] <= sh_line[0]:
      lo_pos += 1
    yield lo[lo_pos] + [ '', '' ] + sh_line

for mixed_line in each_mixed_line(shortdata, longdata):
  print(mixed_line)

Dans de nombreux cas, vous n'avez pas besoin de créer la liste résultante complète, mais à la place, vous pouvez la parcourir comme indiqué avec le print(). C'est beaucoup moins de mémoire et donc recommandé. Mais si vous avez besoin de construire la liste résultante, vous pouvez simplement le faire:

combineddata = list(each_mixed_line(shortdata, longdata))
1
Alfe 17 avril 2018 à 14:17

Si cela ne vous dérange pas de changer votre variable longdata, vous pouvez simplement étendre chaque élément avec les éléments correspondants de shortdata, ce qui est plus efficace, car il alloue un minimum de nouvelles données. Voici le code:

shortdata = [
  ["2015.01.01 22:00:00","1.21036","1.21032","1.21033","1.21038"],
  ["2015.01.01 22:00:02","1.21034","1.21039","1.21038","1.21037"],
  # ...
  ["2015.01.01 22:00:58","1.21041","1.21042","1.21047","1.21050"],
  ["2015.01.01 22:01:00","1.21044","1.21032","1.21033","1.21035"],
  ["2015.01.01 22:01:02","1.21047","1.21033","1.21035","1.21035"],
  # ...
]

longdata = [
  ["2015.01.01 22:00:00","1.21036","1.21032","1.21033","1.21038"],
  ["2015.01.01 22:01:00","1.21044","1.21032","1.21033","1.21035"],
  # ...
]

n = 0
end = len(shortdata)
for long in longdata:
   prefix = long[0][:16]  # keep only significant part
   long.clear()           # because the first line of 'short' is same as 'long'
   while n < end:
     short = shortdata[n]
     if short[0][:16] != prefix: break
     long.extend(short + ['/'])
     n += 1
print(longdata)

Résultat:

[['2015.01.01 22:00:00', '1.21036', '1.21032', '1.21033', '1.21038', '/', 
  '2015.01.01 22:00:02', '1.21034', '1.21039', '1.21038', '1.21037', '/',
  ... 
  '2015.01.01 22:00:58', '1.21041', '1.21042', '1.21047', '1.21050', '/'], 
 ['2015.01.01 22:01:00', '1.21044', '1.21032', '1.21033', '1.21035', '/', 
  '2015.01.01 22:01:02', '1.21047', '1.21033', '1.21035', '1.21035', '/',
  ...
  '2015.01.01 22:01:58', '1.21041', '1.21042', '1.21047', '1.21050', '/'],
 ...
]

Vous pouvez également remplacer le while intérieur par un itérateur sur shortdata mais je ne suis pas sûr que cela accélère vraiment le code. Besoin de le chronométrer ...

0
sciroccorics 17 avril 2018 à 16:01

Si votre liste courte et longue a une relation n times longer (le n serait 30 dans votre exemple)

Soit longtdata: [[1],[2]], shortdata: [[1.1],[1.2]...[1.n],[2.1],[2.2],...,[2.n],[3.1]...]

Alors vous pouvez dépenser les données courtes par

expended_data = (x for l in longtdata for x in [l]*n)

Ou

expended_data = (x for l in longtdata for i in range(n))

Et le combineddata devient

combineddata = [a+["",""]+b for a,b in zip(expended_data,shortdata)]
1
apple apple 19 avril 2018 à 13:34