How to split every 2 lines in Python?

Viewed 720

I have an input which has properties spread on lines, however every subject has one newline with a property. So my input is:

"subject \n
property \n
subject \n
property \n
etc"

I want to separate this input into a list of ["subject \n property" , "subject \n property", etc], however I am rather new to python and it doesn't seem like I am able to use the .splitlines() for every other newline.

Does anyone know whether there is a way in which I can do this with .splitlines() or is there an easier alternative?

7 Answers

You could split on \n, then regroup the items two by two:

Maybe like this:

s = "subject \n property \n subject \n property \n"
s = s.split()
res = []
for idx in range(0, len(s), 2):
    res.append(f'{s[idx]} \n {s[idx+1]}')   # you will have to ensure the number of elements is even, or protect against an Indexerror
    
res

output:

['subject \n property', 'subject \n property']

Inspired from itertools :

def grouper(iterable, n, fillvalue=None):
    "Collect data into fixed-length chunks or blocks"
    # grouper('ABCDEFG', 3, 'x') --> ABC DEF Gxx"
    args = [iter(iterable)] * n
    return zip_longest(*args, fillvalue=fillvalue)

https://docs.python.org/3.10/library/itertools.html

so :

   from itertools import zip_longest
   s = [text.split('\n')] * n # here n = 2
   result = [ '\n'.join(lines).strip() for (*lines,) in zip_longest(*s, fill_value='') ]

(the idea is by doing : [text.split('\n')] * n, you create a list containing n times the same iterator. Using zip_longest, you group using this iterator n times too, and then you get a tuple of n lines each iterations. These lines follow each other since zip_longest calls next on the same iterator. The final strip() handles the case n_lines % n != 0. A more elegant but a bit longer way of handling the last lines would be : result = [ '\n'.join(l for l in lines if l is not None).strip() for (*lines,) in zip_longest(*s) ])

Another simpler to read way :

s = text.split('\n')
res = [ '\n'.join(s[i:i+2]) for i in range(0, len(s) // 2, 2) ]

A bit of functional-style solution where you can zip list slices

>>> text = "subject1\nproperty1\nsubject2\nproperty2"
>>> lines = text.splitlines() 
>>> pairs = zip(lines[0::2], lines[1::2])
>>> list(pairs)
[('subject1', 'property1'), ('subject2', 'property2')]
>>> list(map("\n".join, pairs))
['subject1\nproperty1', 'subject2\nproperty2']

One way I can think is split everything and then stitch it back 2 at a time, there can be a better way

my_str = "subject \n property \n subject \n property \n etc"
all_splits = my_str.split('\n')
ret = []
for i in range(0,len(all_splits),2):
    ret.append(all_splits[i])
    try:ret[-1]+="\n"+all_splits[i+1]
    except: pass
print(ret)
['subject \n property ', ' subject \n property ', ' etc']
s = "subject \nproperty \n subject \nproperty \n etc"
print(s.split(" \n "))
#['subject \nproperty', 'subject \nproperty', 'etc']

I suggest you split the string by each lines using the splitlines() function and from the list obtained, iterate through each even index, add it to an empty string and then add the index that comes after it to the the empty string after a newline.

Take a look at this code:

def your_function(string): #Takes the combined string as input
    list1 = string.splitlines()
    list_to_return = []
    for x in list1:
        if list1.index(x) % 2 == 0:
            list_to_return.append(f'{x} \n {list1[list1.index(x) + 1]}')
    return list_to_return

I believe this code does what you wanted. Make no mistake this is by no means the easiest or most efficient way to do it. But it does get the job done :)

Using re.sub would do it. Remove new lines and spaces ('\n\s') and add a comma after 'property', which can serve as a separator in split:

my_str = "subject \n property \n subject \n property"
my_str2 = re.sub('\n\s', '', my_str)
my_str3 = re.sub('property', 'property, ', my_str2)
my_str4 = re.sub('  subject', 'subject', my_str3)
my_str4.split(",")

Output is:

['subject property', 'subject property', ' ']
Related