2

I have a list of strings and need to remove the sequences of empty strings only at the beginning and end of the list. I need to keep any empty strings that are between non-empty strings.

For example,

my_list = ['', '', 'Sam sits', '', 'Thinking of you.', '', 'All ideas bad.', '', '', '']  

The output should be;

['Sam sits', '', 'Thinking of you.', '', 'All ideas bad.']  

Most methods i have tried to use get rid of the blank lines in the middle too. Any advice would be greatly appreciated.

0

3 Answers 3

6

There is a more efficient way, but if you choose an element that isn't contained in the elements of the list, you can join and strip and split which only removes the element from the front and back, preserving the empty elements in the middle.

>>> '-'.join(my_list).strip('-').split('-')
['Sam sits', '', 'Thinking of you.', '', 'All ideas bad.']

Extending this approach to concatenate longer runs of empty strings in the middle of a list to a single empty string:

import re

def remove_join(arr, el):
    return re.split(r'\{}+()'.format(el), el.join(arr).strip(el))

>>> my_list = ['', '', 'test', '', '', '', 'test2', '', '']
>>> remove_join(my_list, '-')
['test', '', 'test2']
Sign up to request clarification or add additional context in comments.

6 Comments

What if you can't specify a char in advance that isn't in the strings? I guess you could use '\0', since that's pretty unlikely to be used in normal text strings. Failing that, you'd need to scan all the strings first to choose an unused char.
Yea, there are plenty of things wrong with doing it this way, just thought it was clever.
Thank you this worked out well. Although I forgot to add something, if there is multiple blank lines in the middle, is there a way to still have it all be represented by one single empty string ' ' in the output?
So you want to concatenate multiple empty strings in the middle to a single empty string?
Yes exactly just for the ones in the middle.
|
5

Look in the various list methods. You can use searches from left and right, and check to see whether they're the first and last elements. Conversely, simply remove the left-most element as long as it's an undesirable one. For instance:

while my_list[0] == '':
    my_list.pop(0)

while my_list[-1] == '':
    my_list.pop(-1)

For better efficiency (make a new list, but only one list alteration):

# First, form a Boolean list that identifies non-empty elements
has_content = [len(s) > 0 for s in my_list]
# Then find the left and right non-empty elements.
left  = has_content.find(True)    # find the left  non-empty string
right = has_content.rfind(True)   # find the right non-empty string
new_list = my_list[left:right+1]

This doesn't check edge cases, but gives the general idea.

7 Comments

If my_list is empty or gets emptied this will crash.
This is the best answer--it is direct and clear (though you should handle the edge case of the empty list and other such cases.). Programmers should avoid tricky code unless it serves some very strong purpose. The only disadvantage of this code is that it can be slow if the list is long and there are many empty strings at the list's beginning, since removing from the beginning of a string is somewhat slow.
Each .pop(0) call requires all remaining list items to be moved down to fill the gap. So it's not a good idea to call it in a loop.
It's not at all efficient -- but it's easy to understand. Yes, it would be more efficient to find the first non-empty element on each end, and then simply slice the list in one operation.
The new version is much better, and with appropriate tests to handle the edge cases it's probably the best way to do this.
|
4

You can calculate your indices first with next and enumerate. Then slice your list.

my_list = ['', '', 'Sam sits', '', 'Thinking of you.', '', 'All ideas bad.', '', '', '']

idx1 = next(i for i, j in enumerate(my_list) if j)
idx2 = -next(i for i, j in enumerate(reversed(my_list)) if j)

res = my_list[idx1: idx2 if idx2 !=0 else None]

print(res)

['Sam sits', '', 'Thinking of you.', '', 'All ideas bad.']

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.