简体   繁体   中英

More pythonic/elegant way to do this Python string slicing?

So I have a function that takes two string inputs - it slices them so that if of even length, the length of the front segment is the same as that of the back, and if of odd length, the middle character goes to the front segment (ie hello -> hel , lo). And then you mix and match the resulting front and back segments of the two string to produce the final output.

I want to be able to do this all under one function and what I came up with is ugly as all heck:

def front_back(a, b):
    if len(a) % 2 == 0:
        front_a = a[:len(a)/2]
        back_a = a[len(a)/2:]
    elif len(a) % 2 != 0:
        front_a = a[:(len(a)/2)+1]
        back_a = a[(len(a)/2)+1:]
    if len(b) % 2 == 0:
        front_b = b[:len(b)/2]
        back_b = b[len(b)/2:]
    elif len(b) % 2 != 0:
        front_b = b[:(len(b)/2)+1]
        back_b = b[(len(b)/2)+1:]

    print front_a + front_b + back_a + back_b

front_back('Kitten', 'Donut') ---> KitDontenut

Is there a more pythonic/elegant way?

I couldn't figure out how to use lambdas (they can't process the if statement necessary to deal with even and odd length cases... i think?) if that's the way to go...

UPDATE: thanks for the great suggestions everyone. just one more question:

when i try a version with lamdbas, based off a suggestion (for practice), I get a NameError that global name 's' isn't defined. What's wrong with how I wrote the lambda?

def front_back(a, b):
    divideString = lambda s: s[:((1+len(s))//2)], s[((1+len(s))//2):]
    a1, a2 = divideString(a)
    b1, b2 = divideString(b)
    print a1 + b1 + a2 + b2
front_back("hello","cookies")

You are making it more complicated than it needs to be:

def front_back(a, b):
    mid_a, mid_b = (len(a) + 1) // 2, (len(b) + 1) // 2
    front_a, back_a = a[:mid_a], a[mid_a:]
    front_b, back_b = b[:mid_b], b[mid_b:]
    print front_a + front_b + back_a + back_b

By adding 1 before dividing by 2 (floor division), you round up .

Demo:

>>> def front_back(a, b):
...     mid_a, mid_b = (len(a) + 1) // 2, (len(b) + 1) // 2
...     front_a, back_a = a[:mid_a], a[mid_a:]
...     front_b, back_b = b[:mid_b], b[mid_b:]
...     print front_a + front_b + back_a + back_b
... 
>>> front_back('Kitten', 'Donut')
KitDontenut

You could inline the slicing even:

def front_back(a, b):
    mid_a, mid_b = (len(a) + 1) // 2, (len(b) + 1) // 2
    print a[:mid_a] + b[:mid_b] + a[mid_a:] + b[mid_b:]
def divideString(myString):
    sliceHere = ( (1 + len(myString)) // 2)
    return myString[:sliceHere], myString[sliceHere:]

def front_back(a, b):
    a1, a2 = divideString(a)
    b1, b2 = divideString(b)
    return a1 + b1 + a2 + b2
def front_back(a, b):
    return "".join([a[:(len(a)+1)/2]], b[:(len(b)+1)/2], \
        a[(len(a)+1)/2]:], b[:(len(b)+1)/2]])

You could also add the result of length % 2 to the fronts:

def front_back(a, b):
    ln_a, ln_b = len(a), len(b)
    a1 = a2 = ln_a // 2
    b1 = b2 = ln_b // 2
    a1 += ln_a % 2
    b1 += ln_b % 2
    return a[:a1] + b[:b1] + a[-a2:] + b[-b2:]

print(front_back('Kitten', 'Donut'))

There are a some good answers here already, but for the sake of diversity, since you seem to be interested in multiple possibilities, here's a different way of looking at it:

import itertools

def front_back(a,b):
    words = [a,b]
    output = [[],[]]
    for word in words:
        if len(word) % 2 == 0:
            output[0].append(word[:len(word)//2])
            output[1].append(word[len(word)//2:])

        else:
            output[0].append(word[:len(word)//2+1])
            output[1].append(word[(len(word)//2)+1:])

    return "".join(output[0]) + "".join(output[1])

print(front_back('Kitten', 'Donut'))

Interpret with Python 3.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM