Łączenie elementów listy, jeśli elementy te znajdują się między dwoma białymi spacjami

24

Mam takie dane wejściowe:

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

Chcę połączyć elementy między, ''aby uzyskać wynik podobny do tego:

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

Próbowałem użyć joini wyświetlić takie opcje:

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++']

Działa to do pewnego stopnia, ale nie wiem, jak iterować tę instrukcję dla całej listy.

mewtire
źródło

Odpowiedzi:

27

Używanie 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]

Wynik:

['assembly', 'python', 'java', 'ruby', 'javascript', 'c++']
Chris
źródło
2
Objaśnienie: Używa „bool”, aby sprawdzić wartość „Falsey”, np. Pusty ciąg znaków lub None.
noɥʇʎԀʎzɐɹƆ
7

To okropne i zuchwałe, ale

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

może pobrać dowolny ciąg, który może być zagwarantowany, że nie jest zawarty w konkatenacji listy i zwrócić funkcję wykonującą to, co chcesz. Oczywiście prawdopodobnie chcesz użyć tego tylko raz lub dwa razy w konkretnej sytuacji, więc jeśli możesz zagwarantować, że żaden element listy nie zawiera spacji, może wyglądać bardziej jak:

a = ['assembly', '', 'py', 'tho', 'n', '', 'ja', 'va', '', 'rub', 'y', '', 'java', 'script', '', 'c++']
a = ''.join(i or ' ' for i in a).split(' ')
Niepowiązany ciąg
źródło
4

Jeśli nie możesz lub nie chcesz używać 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 = ""
Asad
źródło
3

Możesz to zrobić:

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

Wynik:

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

Edytuj po komentarzach:

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

Wynik:

['assembly', 'python', 'java', 'ruby', 'javascript', 'c++']
naiwny
źródło
# get the indices.nie jest bardzo przydatnym komentarzem. Sugeruję, abyś przydał się (np. filter the indices to keep only those that correspond to whitespace) Lub całkowicie go usunął.
Alexander - Przywróć Monikę
Czy nie można też uprościć tego 2-etapowego procesu indices = [i for s in a if s == '']?
Alexander - przywróć Monikę
@Alexander Myślę, że twoja propozycja dla linii 2 byłaby błędem składni. Wiersz 2 można usunąć, jeśli po prostu dodasz opcję „równa się indx = [i for i, x in enumerate(a) if x == '']
zerowemu ciągowi
Niestety, ta odpowiedź nie uwzględnia pierwszego lub ostatniego elementu, który należy połączyć. jak, a = ['asse','mbly', '', 'py', 'tho', 'n', '', 'ja', 'va', '', 'rub', 'y', '', 'java', 'script', '', 'c+', '+']ale wygląda na to, że możesz poprawić swoją linię 3, dodając listę z łańcuchem zerowym na końcach a enumerate([''] + a + [''])następnie usuwając a[0:indx[0]]i a[indx[-1]+1:]w linii 4. To nadal nie uwzględnia, jeśli obok siebie są dwa ciągi zerowe chociaż
Reimus Klinsman,
1
Dzięki @KeiNagase za dobre komentarze. Zobacz edycję.
naiwny
2

Jeśli ograniczniki wejściowe są faktycznie pustymi łańcuchami, możesz to zrobić

strlist = [x or ' ' for x in a]
joined = ''.join(strlist).split()
joined
['assembly', 'python', 'java', 'ruby', 'javascript', 'c++']
realgeek
źródło
Przepraszamy, nie widziałem odpowiedzi niepowiązanego łańcucha. Jeśli split () bez parametru, zwinie wszystkie białe znaki, co jest nieco bardziej niezawodne.
realgeek
1

Dość stary, ale wciąż przydatny:

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)

To daje

['assembly', 'python', 'java', 'ruby', 'javascript', 'c++']
Jan
źródło
1

uruchom pętlę nad listą
wewnątrz pętli, dodaj element do tymczasowego pustego łańcucha i sprawdź, czy element jest pustym łańcuchem lub ostatnim elementem listy, jeśli to prawda, dodaj zmienną tymczasową do listy wyników i zmień wartość tej zmiennej do pustego ciągu
Kod:

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)

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

Eswar
źródło
1

Zgadzam się, że odpowiedź Cris używa większości podejść pythonowych , ale dobrze będzie dostosować Cris trochę odpowiedź . Zamiast używać groupby(l,key = bool)do używania groupby(l, key = lambda x: x !='')i pozbyć się niepotrzebnej dwuznaczności

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]

Jak stwierdzono w Zen of Python : Jawne jest lepsze niż niejawne

PS Piszę tylko nową odpowiedź, ponieważ nie mam wystarczającej reputacji, aby napisać komentarz na temat Crisa odpowiedzi .

N.Nonkovic
źródło
1

Kolejna działająca wersja z tylko podstawowymi pętlami / testami:

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
B. Idź
źródło