Joindre des éléments d'une liste si ces éléments sont entre deux espaces blancs


24

J'ai une entrée comme celle-ci:

['assembly', '', 'py', 'tho', 'n', '', 'ja', 'va', '', 'rub', 'y', '', 'java', 'script', '', 'c++']

Je veux joindre des éléments entre ''pour avoir une sortie comme celle-ci:

['assembly', 'python', 'java', 'ruby', 'javascript', 'c++']

J'ai essayé d'utiliser joinet de lister les tranches comme ceci:

a=['assembly', '', 'py', 'tho', 'n', '', 'ja', 'va', '', 'rub', 'y', '', 'java', 'script', '', 'c++']
a[2:5] = [''.join(a[ 2: 5])]
a=['assembly', '', 'python', '', 'ja', 'va', '', 'rub', 'y', '', 'java', 'script', '', 'c++']

Cela fonctionne dans une certaine mesure mais je ne sais pas comment répéter cette instruction pour la liste entière.

Réponses:


27

En utilisant itertools.groupby:

from itertools import groupby

l = ['assembly', '', 'py', 'tho', 'n', '', 'ja', 'va', '', 'rub', 'y', '', 'java', 'script', '', 'c++']
new_l = [''.join(g) for k, g in groupby(l, key = bool) if k]

Production:

['assembly', 'python', 'java', 'ruby', 'javascript', 'c++']

2
Explication: Cela utilise "bool" pour rechercher une valeur "Falsey", comme une chaîne vide ou None.
noɥʇʎԀʎzɐɹƆ

7

C'est affreux et hacky, mais

lambda b:lambda l:''.join(i or b for i in l).split(b)

peut prendre n'importe quelle chaîne que vous pouvez garantir n'est pas contenue dans la concaténation de la liste et retourner une fonction faisant ce que vous voulez. Bien sûr, vous ne voudrez probablement l'utiliser qu'une ou deux fois pour votre situation spécifique, donc, si vous pouvez garantir qu'aucun élément de la liste ne contient d'espace, cela pourrait ressembler davantage à:

a = ['assembly', '', 'py', 'tho', 'n', '', 'ja', 'va', '', 'rub', 'y', '', 'java', 'script', '', 'c++']
a = ''.join(i or ' ' for i in a).split(' ')

4

Si vous ne pouvez pas ou ne voulez pas utiliser itertools:

l = ['assembly', '', 'py', 'tho', 'n', '', 'ja', 'va', '', 'rub', 'y', '', 'java', 'script', '', 'c++']
l_new = []
combined = ""
for idx, s in enumerate(l):
    if s != "":
        combined += s
        if idx == len(l)-1:
            l_new.append(combined)

    else:
        l_new.append(combined)
        combined = ""

3

Tu peux le faire:

a = ['assembly', '', 'py', 'tho', 'n', '', 'ja', 'va', '', 'rub', 'y', '', 'java', 'script', '', 'c++']
indx = ['' == k for k in a]
indx = [i for i, x in enumerate(indx) if x] # get the indices.
a_merged = a[0:indx[0]] + [''.join(a[indx[i]:indx[i+1]]) for i in range(len(indx)) if i < len(indx)-1] + a[indx[-1]+1:] # merge the list

Production:

['assembly', 'python', 'java', 'ruby', 'javascript', 'c++']

Modifier après les commentaires:

a = ['assembly', '','',  'py', 'tho', 'n', '', 'ja', 'va', '', 'rub', 'y', '', 'java', 'script', '', 'c++']
indx = [i for i, x in enumerate(a) if x == ''] # get the indices where '' occurs in the original list. 
a_merged = a[0:indx[0]] + [''.join(a[indx[i]:indx[i+1]]) for i in range(len(indx)) if i < len(indx)-1 and indx[i+1] -indx[i] > 1] + a[indx[-1]+1:]
a_merged

Production:

['assembly', 'python', 'java', 'ruby', 'javascript', 'c++']

# get the indices.n'est pas un commentaire très utile. Je vous suggère soit de le rendre utile (par exemple filter the indices to keep only those that correspond to whitespace), soit de le supprimer entièrement.
Alexander - Reinstate Monica

De plus, ce processus en 2 étapes ne pourrait-il pas simplement être simplifié indices = [i for s in a if s == '']?
Alexander - Reinstate Monica

@Alexander Je pense que votre suggestion pour la ligne 2 serait une erreur de syntaxe. La ligne 2 peut être supprimée si vous ajoutez simplement la coche "est égal à une chaîne nulle" à la ligne trois commeindx = [i for i, x in enumerate(a) if x == '']
Reimus Klinsman

Malheureusement, cette réponse ne tient pas compte du fait que le premier ou le dernier élément doit être joint. comme a = ['asse','mbly', '', 'py', 'tho', 'n', '', 'ja', 'va', '', 'rub', 'y', '', 'java', 'script', '', 'c+', '+']mais il semble que vous pourriez améliorer votre ligne 3 en ajoutant une liste avec une chaîne nulle aux extrémités d'un enumerate([''] + a + [''])puis en supprimant le a[0:indx[0]]et a[indx[-1]+1:]sur votre ligne 4. Cela ne tient toujours pas compte s'il y a deux chaînes nulles juste à côté l'une de l'autre cependant
Reimus Klinsman

1
Merci @KeiNagase pour les bons commentaires. Voir l'édition.
naïf

2

Si les délimiteurs d'entrée sont en fait des chaînes vides, vous pouvez le faire

strlist = [x or ' ' for x in a]
joined = ''.join(strlist).split()
joined
['assembly', 'python', 'java', 'ruby', 'javascript', 'c++']

Désolé, je n'ai pas vu la réponse de Unrelated String. Si vous divisez () sans paramètre, il réduira tous les espaces blancs, ce qui est un peu plus robuste.
realgeek

1

Assez vieux mais toujours utile:

from itertools import groupby

lst = ['assembly', '', 'py', 'tho', 'n', '', 'ja', 'va', '', 'rub', 'y', '', 'java', 'script', '', 'c++']

new_lst = [''.join(values)
           for key, values in groupby(lst, key = lambda x: x == '')
           if not key]
print(new_lst)

Cela donne

['assembly', 'python', 'java', 'ruby', 'javascript', 'c++']

1

exécuter une boucle sur la liste
à l'intérieur de la boucle ajouter l'élément à une chaîne vide temporaire et vérifier la condition si l'élément est une chaîne vide ou le dernier élément de la liste, si vrai, ajouter la variable temporaire à la liste de sortie et modifier la valeur de cette variable dans une chaîne vide
Code:

x=['assembly', '', 'py', 'tho', 'n', '', 'ja', 'va', '', 'rub', 'y', '', 'java', 'script', '', 'c++']
temp=''
output=[]
for y in x:
    temp=temp+y
    if y=='' or y==x[-1]:
        output.append(temp)
        temp=''

print(output)

Production: ['assembly', 'python', 'java', 'ruby', 'javascript', 'c++']


1

Je conviens que la réponse Cris utilise la plupart des approches python , mais il sera bon d'adapter un peu la réponse Cris . Au lieu d'utiliser groupby(l,key = bool)pour utiliser groupby(l, key = lambda x: x !='')et se débarrasser de l' ambiguïté inutile

from itertools import groupby

separator = ''
l = ['assembly', '', 'py', 'tho', 'n', '', 'ja', 'va', '', 'rub', 'y', '', 'java', 'script', '', 'c++']
new_l = [''.join(g) for k, g in groupby(l, key = lambda x: x !=separator) if k]

Comme il est indiqué dans Le Zen de Python : explicite vaut mieux qu'implicite

PS J'écris seulement la nouvelle réponse parce que je n'ai pas assez de réputation pour écrire un commentaire sur la réponse de Cris .


1

Une autre version de travail, avec seulement des boucles / tests de base:

txt = ['assembly', '', 'py', 'tho', 'n', '', 'ja', 'va', '', 'rub', 'y', '', 'java', 'script', '', 'c++']

out = []
temp = ''

for s in txt:
   if s == '':
      if temp != '':
         out.append(temp) 
         temp = ''
      out.append('')
   else:
      temp = temp + s

if temp != '':
   out.append(temp)

out
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.